跨域问题其实之前就有说过,不明白的可以参考我之前的文章,这章主要讲解SpringBoot CROS的支持。
这里主要按照官方文档方式讲述。
SpringBoot CROS 参考: http://docs.spring.io/spring-boot/docs/1.5.4.RELEASE/reference/htmlsingle/#boot-features-cors
Spring CROS 参考: http://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/htmlsingle/#cors
package cn.saytime.web;
import cn.saytime.bean.JsonResult;
import cn.saytime.bean.User;
import org.springframework.http.ResponseEntity;
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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zh
* @ClassName cn.saytime.web.UserController
* @Description
*/
@RestController
public class UserController {
// 创建线程安全的Map
static Map users = Collections.synchronizedMap(new HashMap());
/**
* 根据ID查询用户
* @param id
* @return
*/
@RequestMapping(value = "user/{id}", method = RequestMethod.GET)
public ResponseEntity getUserById (@PathVariable(value = "id") Integer id){
JsonResult r = new JsonResult();
try {
User user = users.get(id);
r.setResult(user);
r.setStatus("ok");
} catch (Exception e) {
r.setResult(e.getClass().getName() + ":" + e.getMessage());
r.setStatus("error");
e.printStackTrace();
}
return ResponseEntity.ok(r);
}
/**
* 查询用户列表
* @return
*/
@CrossOrigin
@RequestMapping(value = "users", method = RequestMethod.GET)
public ResponseEntity getUserList (){
JsonResult r = new JsonResult();
try {
List userList = new ArrayList(users.values());
r.setResult(userList);
r.setStatus("ok");
} catch (Exception e) {
r.setResult(e.getClass().getName() + ":" + e.getMessage());
r.setStatus("error");
e.printStackTrace();
}
return ResponseEntity.ok(r);
}
/**
* 添加用户
* @param user
* @return
*/
@RequestMapping(value = "user", method = RequestMethod.POST)
public ResponseEntity add (@RequestBody User user){
JsonResult r = new JsonResult();
try {
users.put(user.getId(), user);
r.setResult(user.getId());
r.setStatus("ok");
} catch (Exception e) {
r.setResult(e.getClass().getName() + ":" + e.getMessage());
r.setStatus("error");
e.printStackTrace();
}
return ResponseEntity.ok(r);
}
/**
* 根据id删除用户
* @param id
* @return
*/
@RequestMapping(value = "user/{id}", method = RequestMethod.DELETE)
public ResponseEntity delete (@PathVariable(value = "id") Integer id){
JsonResult r = new JsonResult();
try {
users.remove(id);
r.setResult(id);
r.setStatus("ok");
} catch (Exception e) {
r.setResult(e.getClass().getName() + ":" + e.getMessage());
r.setStatus("error");
e.printStackTrace();
}
return ResponseEntity.ok(r);
}
/**
* 根据id修改用户信息
* @param user
* @return
*/
@RequestMapping(value = "user/{id}", method = RequestMethod.PUT)
public ResponseEntity update (@PathVariable("id") Integer id, @RequestBody User user){
JsonResult r = new JsonResult();
try {
User u = users.get(id);
u.setUsername(user.getUsername());
u.setAge(user.getAge());
users.put(id, u);
r.setResult(u);
r.setStatus("ok");
} catch (Exception e) {
r.setResult(e.getClass().getName() + ":" + e.getMessage());
r.setStatus("error");
e.printStackTrace();
}
return ResponseEntity.ok(r);
}
}
User.class
package cn.saytime.bean;
import java.util.Date;
/**
* @author zh
* @ClassName cn.saytime.bean.User
* @Description
*/
public class User {
private int id;
private String username;
private int age;
private Date ctm;
// Getter Setter
}
JsonResult.class
package cn.saytime.bean;
public class JsonResult {
private String status = null;
private Object result = null;
// Getter Setter
}
二、测试是否存在跨域问题
我们在static目录新建一个test.html
Title
我们使用IDEA的浏览器预览功能,点击谷歌小图标,可以看到打开网址为: http://localhost:63342/springboot-demo/springboot-cros/static/test.html?_ijt=ibtt432ffb9rh0vffqkkug3je8
启动SpringBoot工程,默认8080
不是使用IDEA的用户,自己找个tomcat启动test.html页面,修改端口为其他,然后启动springboot。
所以证明存在跨域问题。
一、@CrossOrigin注解方式 Controller method CORS configuration
这里我们在users映射的方法getUserList上面加上@CrossOrigin
@CrossOrigin
@RequestMapping(value = "users", method = RequestMethod.GET)
public ResponseEntity getUserList ()
然后再次使用上面的方式访问。
![在这里插入图片描述](https://img-blog.csdn.net/20170710213931410?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2F5dGltZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
表示跨域问题解决。 default @CrossOrigin allows all origins and the HTTP methods specified in the @RequestMapping annotation 上面的官方文档说明,也就是默认的@CrossOrigin允许所有跨域请求。
通过查看CrossOrigin源码可以看到, 默认配置为:
“Access-Control-Allow-Origin” : “*”
“Access-Control-Allow-Methods” : “GET,POST,PUT,OPTIONS”
“Access-Control-Allow-Credentials” : “true”
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
/** @deprecated /
@Deprecated
String[] DEFAULT_ORIGINS = new String[]{""};
/** @deprecated /
@Deprecated
String[] DEFAULT_ALLOWED_HEADERS = new String[]{""};
/** @deprecated /
@Deprecated
boolean DEFAULT_ALLOW_CREDENTIALS = true;
/* @deprecated */
@Deprecated
long DEFAULT_MAX_AGE = 1800L;
@AliasFor("origins")
String[] value() default {};
@AliasFor("value")
String[] origins() default {};
String[] allowedHeaders() default {};
String[] exposedHeaders() default {};
RequestMethod[] methods() default {};
String allowCredentials() default "";
long maxAge() default -1L;
}
It is also possible to enable CORS for the whole controller 也可以用在整个Controller类上面。即该controller所有映射都支持跨域请求。
@CrossOrigin(origins = “http://domain2.com”,
maxAge = 3600,
methods = {RequestMethod.GET, RequestMethod.POST})
@RestController
public class UserController
二、全局CORS配置
Global CORS configuration In addition to fine-grained, annotation-based configuration you’ll probably want to define some global CORS configuration as well. This is similar to using filters but can be declared withing Spring MVC and combined with fine-grained @CrossOrigin configuration. By default all origins and GET, HEAD and POST methods are allowed.
package cn.saytime.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
@author zh
@ClassName cn.saytime.config.CORSConfiguration
@Description
*/
@Configuration
public class CORSConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/api/");
registry.addMapping("/")
.allowedOrigins(“http://domain.com”, “http://domain2.com”)
.allowedMethods(“GET”, “POST”, “DELETE”, “PUT”, “OPTIONS”)
.allowCredentials(false).maxAge(3600);
}
};
}
}
三、过滤器实现跨域 Filter based CORS support
@Configuration
public class MyConfiguration {
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(false);
config.addAllowedOrigin("http://domain.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}