@RequestBody @Reponsebody
@RequestBody 将请求体的json数据转换为java对象
@Reponsebody 将java对象转换为json
一般前后端分离的项目采用的交互的格式都是json,所以可以直接在controller类上添加@Reponsebody
,这就不必在每个方法上都添加了。
controller类通常需要添加@Reponsebody
和@Controller
两个注解,springmvc将其整合成了一个注解@RestController
@ModelAttribute
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class UserController {
/**
@ModelAttribute 标记在方法上
执行controller中任意一个方法时,都会先执行一次这个方法
并且可以向其他方法中传递参数
*/
@ModelAttribute
public User findUser(){
User user = new User();
user.setId(1);
user.setName("zs");
return user;
}
@RequestMapping("/hello")
public void hello(User user){
user.setId(2);
System.out.println(user);
}
}
@RestController
@RequestMapping("/user")
public class UserController {
@ModelAttribute
public void findUser(Model model){
User user = new User();
user.setId(1);
user.setName("zs");
model.addAttribute("user",user);
}
@RequestMapping("/hello")
public void hello(@ModelAttribute("user") User user){
user.setId(2);
System.out.println(user);
}
}
@SessionAttributes
package com.itheima.controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;
@RestController
@RequestMapping("/user")
@SessionAttributes(names = {"username","id"})
public class UserController {
// 将数据存储到session域中
// 存储也可以使用modelMap
@RequestMapping("/saveSesion")
public void saveSesion(Model model){
model.addAttribute("username","zs");
model.addAttribute("id","10");
}
@RequestMapping("/getSessionAttributes")
public void getSessionAttributes(ModelMap modelMap){
Object username = modelMap.get("username");
Object id = modelMap.get("id");
System.out.println(id);
System.out.println(username);
}
// 清除session中数据
@RequestMapping("/cleanSession")
public void hi(SessionStatus sessionStatus){
sessionStatus.setComplete();
}
}
@ControllerAdvice
这是一个增强controller,可以实现三个方面的功能
- 全局异常处理
- 全局数据绑定
- 全局数据预处理
灵活使用这三个功能,可以帮助我们简化很多工作,需要注意的是,这是 SpringMVC 提供的功能,在 Spring Boot 中可以直接使用
,下面分别来看。
全局异常处理
使用 @ControllerAdvice 实现全局异常处理,只需要定义类,添加该注解即可定义方式如下:
@ControllerAdvice
public class MyGlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ModelAndView customException(Exception e) {
ModelAndView mv = new ModelAndView();
mv.addObject("message", e.getMessage());
mv.setViewName("myerror");
return mv;
}
}
在该类中,可以定义多个方法,不同的方法处理不同的异常,例如专门处理空指针的方法、专门处理数组越界的方法…,也可以直接向上面代码一样,在一个方法中处理所有的异常信息。
@ExceptionHandler
注解用来指明异常的处理类型,即如果这里指定为 NullpointerException,则数组越界异常就不会进到这个方法中来。
全局数据绑定
全局数据绑定功能可以用来做一些初始化
的数据操作,我们可以将一些公共的数据定义在添加了@ControllerAdvice 注解的类中,这样,在每一个 Controller 的接口中
,就都能够访问这些数据。
使用步骤,首先定义全局数据,如下:
@ControllerAdvice
public class MyGlobalExceptionHandler {
@ModelAttribute(name = "md")
public Map<String,Object> mydata() {
HashMap<String, Object> map = new HashMap<>();
map.put("age", 99);
map.put("gender", "男");
return map;
}
}
使用 @ModelAttribute 注解标记该方法的返回数据是一个全局数据,默认情况下,这个全局数据的 key 就是返回的变量名,value 就是方法返回值,当然开发者可以通过 @ModelAttribute 注解的 name 属性去重新指定 key。
定义完成后,在任何一个Controller 的接口中,都可以获取到这里定义的数据:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(Model model) {
Map<String, Object> map = model.asMap();
System.out.println(map);
int i = 1 / 0;
return "hello controller advice";
}
}
全局数据预处理
考虑我有两个实体类,Book 和 Author,分别定义如下:
public class Book {
private String name;
private Long price;
//getter/setter
}
public class Author {
private String name;
private Integer age;
//getter/setter
}
此时,如果我定义一个数据添加接口,如下:
@PostMapping("/book")
public void addBook(Book book, Author author) {
System.out.println(book);
System.out.println(author);
}
这个时候,添加操作就会有问题,因为两个实体类都有一个 name 属性
,从前端传递时 ,无法区分。此时,通过 @ControllerAdvice 的全局数据预处理可以解决这个问题
解决步骤如下:
给接口中的变量取别名
@PostMapping("/book")
public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {
System.out.println(book);
System.out.println(author);
}
进行请求数据预处理
在 @ControllerAdvice 标记的类中添加如下代码:
@InitBinder("b")
public void b(WebDataBinder binder) {
binder.setFieldDefaultPrefix("b.");
}
@InitBinder("a")
public void a(WebDataBinder binder) {
binder.setFieldDefaultPrefix("a.");
}
@InitBinder(“b”)
注解表示该方法用来处理和Book和相关的参数,在方法中,给参数添加一个 b 前缀,即请求参数要有b前缀.
发送请求
请求发送时,通过给不同对象的参数添加不同的前缀,可以实现参数的区分.
@CrossOrigin
@CrossOrigin
解决的是跨域问题
跨域
,域名、端口、协议任一不同都称之为跨域。
controller配置CORS
controller方法的CORS配置
你可以向@RequestMapping
注解处理程序方法添加一个@CrossOrigin注解,以便启用CORS(默认情况下,@CrossOrigin允许在@RequestMapping注解中指定的所有源和HTTP方法):
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
其中@CrossOrigin中的2个参数
:
origins
: 允许可访问的域列表
maxAge
:准备响应前的缓存持续的最大时间(以秒为单位)。
为整个controller启用@CrossOrigin
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
在这个例子中,对于retrieve()和remove()处理方法都启用了跨域支持,还可以看到如何使用@CrossOrigin属性定制CORS配置。
同时使用controller和方法级别的CORS配置
Spring将合并两个注释属性以创建合并的CORS配置。
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin(origins = "http://domain2.com")
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
如果正在使用Spring Security
请确保在Spring安全级别启用CORS,并允许它利用Spring MVC级别定义的配置。
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
}
全局CORS配置
除了细粒度、基于注释的配置之外,您还可能需要定义一些全局CORS配置。这类似于使用筛选器
,但可以声明为Spring MVC并结合
细粒度@CrossOrigin配置。默认情况下,所有origins and GET, HEAD and POST methods是允许的。
JavaConfig使整个应用程序的CORS简化为:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
如果你正在使用Spring Boot
,建议将WebMvcConfigurer bean声明如下:
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
}
你可以轻松地更改任何属性,以及仅将此CORS配置应用到特定的路径模式:
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
如果你正在使用Spring Security,请确保在Spring安全级别启用CORS,并允许它利用Spring MVC级别定义的配置。
基于过滤器的CORS支持
作为上述其他方法的替代,Spring框架还提供了CorsFilter
。在这种情况下,不用使用@CrossOrigin或WebMvcConfigurer#addCorsMappings(CorsRegistry)
,例如,可以在Spring Boot应用程序中声明如下的过滤器:
@Configuration
public class MyConfiguration {
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
spring注解@CrossOrigin不起作用的原因
-
是springMVC的版本要在4.2或以上版本才支持@CrossOrigin
-
非@CrossOrigin没有解决跨域请求问题,而是不正确的请求导致无法得到预期的响应,导致浏览器端提示跨域问题。
-
在Controller注解上方添加@CrossOrigin注解后,仍然出现跨域问题,解决方案之一就是:
在@RequestMapping注解中没有指定Get、Post方式,具体指定后,问题解决。
类似代码如下:
@CrossOrigin
@RestController
public class person{
@RequestMapping(method = RequestMethod.GET)
public String add() {
// 若干代码
}
}
所谓经验,就是经常体验。
部分内容转载自:
https://blog.csdn.net/hhx0626/article/details/71157634
https://blog.csdn.net/qq_18671415/article/details/109275495