标注在类上,类中的方法返回值均为json字符串
等同于 @Controller+@RequestBody
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
/**
* 设置的spring bean 的id
*/
@AliasFor(annotation = Controller.class)
String value() default "";
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
/** 映射名字 */
String name() default "";
/**
* 可以同时定义多个字符串值来接收多个URL请求
*/
@AliasFor("path")
String[] value() default {};
/**
* 和value()作用一样,可以同时定义多个字符串值来接收多个URL请求
*/
@AliasFor("value")
String[] path() default {};
/**
* 请求方法方式主要有: GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.
*/
RequestMethod[] method() default {};
/**
* 限制请求参数(参数匹配才会进入),追加在url上的键值对,多个参数以&分割
* 如:http://127.0.0.1:8080/user/get1?name=zhangsan&&age=22
* 使用:@RequestMapping(path = "/login", params={"name=kolbe","age=123456"})
*/
String[] params() default {};
/**
* 限制请求头(请求头匹配才会进入)
* 如"Host=localhost:8080",也支持"!=" 如"My-Header!=myValue"
* Accept 和 Content-Type 也支持通配符*的写法
* 使用:@RequestMapping(path = "/login", headers="Host=localhost:8080")
*/
String[] headers() default {};
/**
* 限制请求头中的“Content-Type”值,客户端请求实体对应的MIME类型(Contect-Type:application/x-www-form-urlencoded)
* 使用:@RequestMapping(path = "/login", consumes = "text/plain")
* consumes = "text/plain"
* consumes = {"text/plain", "application/*"}
* consumes = MediaType.TEXT_PLAIN_VALUE
*/
String[] consumes() default {};
/**
* 限制请求头中的“Accept”值,客户端能够接收的MIME类型(Accept:text/html,application/xml)
* 使用:@RequestMapping(path = "/login", produces = "text/plain;charset=UTF-8")
* produces = "text/plain"
* produces = {"text/plain", "application/*"}
* produces = MediaType.TEXT_PLAIN_VALUE
* produces = "text/plain;charset=UTF-8"
*/
String[] produces() default {};
}
/**
* 请求方法定义
*/
public enum RequestMethod {
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}
用于HTTP协义交互的信息被称为HTTP报文,客户端发送的HTTP报文被称为请求报文,服务器发回给客户端的HTTP报文称为响应报文,报文由报文头部和报文体组成。
请求头部(Request Headers):请求头包含许多有关客户端环境和请求正文的信息,例如浏览器支持的语言、请求的服务器地址、客户端的操作系统等。
响应头部(Rsponse Headers):响应头也包含许多有用的信息,包括服务器类型、日期、响应内容的类型及编码,响应内容的长度等等。
示列
Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Cookie:JSESSIONID=210075B5E521CWE3CDE938076295A57A
Host:localhost:8080
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93
增强的 Controller,@Controller的作用
可以实现三个方面的功能
当Controller抛出的某个异常多个@ExceptionHandler标注的方法都适用时,Spring会选择最具体的异常处理方法来处理,也就是说@ExceptionHandler(Exception.class)这里标注的方法优先级最低,只有当其它方法都不适用时,才会来到这里处理
axios.get('http://127.0.0.1:8080/dept/get1', {
params: {
name: '测试部门',
info: '测试部门'
}
})
.then(function (response) {
if (response.data.code === 200) {
_this.info1 = response.data.data;
} else {
_this.info1 = response.data.message;
}
})
.catch(function (error) {
console.log(error);
});
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public ApiResult customException(Exception e) {
log.info("优先级更高的异常", e);
return ApiResult.fial("后台出错了");
}
@ExceptionHandler(Exception.class)
@ResponseBody
public ApiResult customAllException(Exception e) {
log.info("优先级最低的异常", e);
return ApiResult.fial("后台出错了");
}
}
@GetMapping("/get1")
public ApiResult get1(@RequestParam String name, @RequestParam String info) {
log.info("部门名:{}, 信息:{}", name, info);
int a = 1/0;
return ApiResult.ok(name);
}
每次接口调用前做一些初始化的数据操作
axios.get('http://127.0.0.1:8080/dept/get2', {
params: {
name: '测试部门',
info: '测试部门'
}
})
.then(function (response) {
_this.info1 = response.data.data;
})
.catch(function (error) {
console.log(error);
});
@ControllerAdvice
public class InitDataHandler {
@ModelAttribute(name = "myDept")
public Dept initData() {
Dept dept = new Dept();
dept.setName("开发部");
dept.setInfo("开发部");
return dept;
}
}
Model 接收初始化的数据,
@GetMapping("/get2")
public ApiResult get2(@RequestParam String name, @RequestParam String info, Model model) {
Map<String, Object> map = model.asMap();
//由@ModelAttribute 的name决定key
Dept dept = (Dept) map.get("myDept");
log.info("部门名:{}, 信息:{}", dept.getName(), dept.getInfo());
return ApiResult.ok(dept.getName());
}
User和Dept两个实体类都有一个 name 属性,从前端传递时 ,无法区分
axios.get('http://127.0.0.1:8080/dept/get3', {
params: {
'u.name': 'lisi',
'u.age': 24,
'd.name': '测试部门',
'd.info': '测试部门'
}
})
.then(function (response) {
_this.info1 = response.data.data;
})
.catch(function (error) {
console.log(error);
});
@ControllerAdvice
public class DataPreHandler {
@InitBinder("u")
public void user(WebDataBinder binder) {
binder.setFieldDefaultPrefix("u.");
}
@InitBinder("d")
public void dept(WebDataBinder binder) {
binder.setFieldDefaultPrefix("d.");
}
}
@GetMapping("/get3")
public ApiResult get3(@ModelAttribute("u")User user, @ModelAttribute("d") Dept dept) {
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
log.info("部门名:{}, 信息:{}", dept.getName(), dept.getInfo());
return ApiResult.ok(dept.getName());
}
增强的 RestController,@RestController的作用
用法和@ControllerAdvice一样
获取Cookie中的值
document.cookie="name=潘总;path=/"
document.cookie="info=18;path=/"
axios.get('http://127.0.0.1:8080/dept/get4', {
withCredentials: true
})
.then(function (response) {
_this.info1 = response.data.data;
})
.catch(function (error) {
console.log(error);
});
@GetMapping("/get4")
public ApiResult get4(@CookieValue("name") String name, @CookieValue String info) {
log.info("部门名:{}, 信息:{}", name, info);
return ApiResult.ok(name);
}
解决跨域问题
document.cookie="name=潘总;path=/"
document.cookie="info=18;path=/"
axios.get('http://127.0.0.1:8080/dept/get4', {
withCredentials: true
})
.then(function (response) {
_this.info1 = response.data.data;
})
.catch(function (error) {
console.log(error);
});
@GetMapping("/get4")
@CrossOrigin(origins = "*", allowCredentials="true", methods=RequestMethod.GET)
public ApiResult get4(@CookieValue("name") String name, @CookieValue String info) {
log.info("部门名:{}, 信息:{}", name, info);
return ApiResult.ok(name);
}
get1
axios.get('http://127.0.0.1:8080/user/get1?name=zhangsan&&age=22')
.then(response => {
this.info = response.data.data
})
.catch(function (error) { // 请求失败处理
console.log(error);
});
axios.get('http://127.0.0.1:8080/user/get1', {
params: {
name: 'lisi',
age: 24
}
})
.then(function (response) {
_this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
});
axios({
method:'get',
url:'http://127.0.0.1:8080/user/get1',
params: {
name: 'Fred',
age: 22
}
})
.then(function(response) {
_this.info = response.data.data;
});
@GetMapping("/get1")
public ApiResult get1(String name, Integer age) {
log.info("姓名:{}, 年龄:{}", name, age);
return ApiResult.ok(name);
}
//对象不能加 @RequestParam
@GetMapping("/get1")
public ApiResult get1(User user) {
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
return ApiResult.ok(user.getName());
}
@GetMapping("/get1")
public ApiResult get1(@RequestParam String name, @RequestParam Integer age) {
log.info("姓名:{}, 年龄:{}", name, age);
return ApiResult.ok(name);
}
get2
axios.get('http://127.0.0.1:8080/user/get2/wangwu/25')
.then(response => {
this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// 总是执行
});
@GetMapping("/get2/{name}/{age}")
public ApiResult get2(@PathVariable String name, @PathVariable Integer age) {
log.info("姓名:{}, 年龄:{}", name, age);
return ApiResult.ok(name);
}
get3
axios.get('http://127.0.0.1:8080/user/get3/wangwu', {
params: {
age: 24
}
})
.then(response => {
this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// 总是执行
});
@GetMapping("/get3/{name}")
public ApiResult get3(@PathVariable String name, @RequestParam Integer age) {
log.info("姓名:{}, 年龄:{}", name, age);
return ApiResult.ok(name);
}
delete和get用法一致,get支持的,delete都支持
axios.delete('http://127.0.0.1:8080/user/delete1', {
params: {
name: 'lisi',
age: 24
}
})
.then(function (response) {
_this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
});
@DeleteMapping("/delete1")
public ApiResult delete1(@RequestParam String name, @RequestParam Integer age) {
log.info("姓名:{}, 年龄:{}", name, age);
return ApiResult.ok(name);
}
post1
axios.post('http://127.0.0.1:8080/user/post1', {
name: 'Fred',
age: 20
})
.then(response => {
this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
});
axios({
method: 'post',
url: 'http://127.0.0.1:8080/user/post1',
data: {
name: 'Fred',
age: 22
}
})
.then( response => {
this.info = response.data.data;
});
@PostMapping("/post1")
public ApiResult post1(@RequestBody String jsonStr) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
User user = objectMapper.readValue(jsonStr, User.class);
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
return ApiResult.ok(user.getName());
}
@PostMapping("/post1")
public ApiResult post1(@RequestBody User user) {
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
return ApiResult.ok(user.getName());
}
post2
axios.post('http://127.0.0.1:8080/user/post2?method=post&&index=2', {
name: 'Fred',
age: 20
})
.then(response => {
this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
});
@PostMapping("/post2")
public ApiResult post2(String method, Integer index, @RequestBody User user) {
log.info("方法:{}, 序号:{}", method, index);
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
return ApiResult.ok(user.getName());
}
@PostMapping("/post2")
public ApiResult post2(@RequestParam String method, @RequestParam Integer index, @RequestBody User user) {
log.info("方法:{}, 序号:{}", method, index);
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
return ApiResult.ok(user.getName());
}
post3
axios.post('http://127.0.0.1:8080/user/post3/post?index=3', {
name: 'Fred',
age: 20
})
.then(response => {
this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
});
@PostMapping("/post3/{method}")
public ApiResult post3(@PathVariable String method, @RequestParam Integer index, @RequestBody User user) {
log.info("方法:{}, 序号:{}", method, index);
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
return ApiResult.ok(user.getName());
}
post4
axios.post('http://127.0.0.1:8080/user/post4',"name='admin'&age=20")
.then(response => {
this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
});
@PostMapping("/post4")
public ApiResult post4(@RequestParam String name, @RequestParam Integer age) {
log.info("姓名:{}, 年龄:{}", name, age);
return ApiResult.ok(name);
}
put和post用法一致,post支持的,put都支持
axios.put('http://127.0.0.1:8080/user/put1', {
name: 'Fred',
age: 20
})
.then(response => {
this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
});
@PutMapping("/put1")
public ApiResult put1(@RequestBody String jsonStr) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
User user = objectMapper.readValue(jsonStr, User.class);
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
return ApiResult.ok(user.getName());
}
@PutMapping("/put1")
public ApiResult put1(@RequestBody User user) {
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
return ApiResult.ok(user.getName());
}
在url中传递参数
axios.get('http://127.0.0.1:8080/user/get1?name=zhangsan&&age=22')
.then(response => {
this.info = response.data.data
})
.catch(function (error) { // 请求失败处理
console.log(error);
});
axios.get('http://127.0.0.1:8080/user/get1', {
params: {
name: 'lisi',
age: 24
}
})
.then(function (response) {
_this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
});
axios({
method:'get',
url:'http://127.0.0.1:8080/user/get1',
params: {
name: 'Fred',
age: 22
}
})
.then(function(response) {
_this.info = response.data.data;
});
@GetMapping("/get1")
public ApiResult get1(@RequestParam String name, @RequestParam Integer age) {
log.info("姓名:{}, 年龄:{}", name, age);
return ApiResult.ok(name);
}
@RequestPart这个注解用在multipart/form-data表单提交请求的方法上
适用于复杂的请求域(像JSON,XML)。
//单文件上传
@RequestMapping("uploadFile")
public ApiResult uploadFile(@RequestPart("file") MultipartFile file, @RequestParam String bucket){
String fileUrl = aliossService.uploadFile(file, bucket);
Map<String,String> result = new HashMap<>();
result.put("fileUrl",fileUrl);
return ApiResult.ok("success");
}
//多文件上传
@RequestMapping("uploadFile")
public ApiResult uploadFiles(@RequestPart("uploadFile") List<MultipartFile> uploadFiles, @RequestPart("user") User user, ApiResult) {
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
uploadFiles.forEach(file -> aliossService.uploadFile(file, bucket);
return ApiResult.ok("success");
}
在方法体中传递传输
接收前端传递给后端的json字符串,也可以封装成对象
axios.post('http://127.0.0.1:8080/user/post1', {
name: 'Fred',
age: 20
})
.then(response => {
this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
});
axios({
method: 'post',
url: 'http://127.0.0.1:8080/user/post1',
data: {
name: 'Fred',
age: 22
}
})
.then( response => {
this.info = response.data.data;
});
@PostMapping("/post1")
public ApiResult post1(@RequestBody String jsonStr) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
User user = objectMapper.readValue(jsonStr, User.class);
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
return ApiResult.ok(user.getName());
}
@PostMapping("/post1")
public ApiResult post1(@RequestBody User user) {
log.info("姓名:{}, 年龄:{}", user.getName(), user.getAge());
return ApiResult.ok(user.getName());
}
标注在类上,类中的方法返回值均为json字符串
@Controller+@RequestBody 等同于 @RestController
标注在方法上,方法返回json字符串
@RequestMapping+@RequestBody 等同于 @GetMapping等
@RequestMapping(path = "/get1", method = RequestMethod.GET)
@ResponseBody
public ApiResult get1(String name, Integer age) {
log.info("姓名:{}, 年龄:{}", name, age);
return ApiResult.ok(name);
}
axios.get('http://127.0.0.1:8080/user/get3/wangwu', {
params: {
age: 24
}
})
.then(response => {
this.info = response.data.data;
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// 总是执行
});
@GetMapping("/get3/{name}")
public ApiResult get3(@PathVariable String name, @RequestParam Integer age) {
log.info("姓名:{}, 年龄:{}", name, age);
return ApiResult.ok(name);
}
@RequestAttribute只负责从request里面取属性值
放值的方式有下面三种
axios.get('http://127.0.0.1:8080/dept/get5')
.then(function (response) {
_this.info1 = response.data.data;
})
.catch(function (error) {
console.log(error);
});
@ModelAttribute
public Map<String, String> personModelAttr(HttpServletRequest request) {
request.setAttribute("data", "request中放的数据");
Map<String, String> map = new HashMap<>();
map.put("data", "request中放的数据");
return map;
}
@GetMapping("/get5")
public ApiResult get5(@RequestAttribute String data, HttpServletRequest request) {
log.info("@RequestAttribute注解获取:{}", data);
log.info("HttpServletRequest中获取:{}", request.getAttribute("data"));
return ApiResult.ok(data);
}
拦截器实现
public class RequestAttrInterceptor implements HandlerInterceptor {
/**
* 在请求处理之前进行调用(Controller方法调用之前)
* 返回false,请求到此结束; 返回true,请求继续执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setAttribute("data", "request中放的数据");
return true;
}
/**
* 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
* 此时可以通过modelAndView对模型数据进行处理或对视图进行处理
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
/**
* 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行
* 可以在此记录结束时间并输出消耗时间,进行资源清理工作
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
@Configuration
public class CorsConfig implements WebMvcConfigurer {
//注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration registration = registry.addInterceptor(new RequestAttrInterceptor());
//所有路径都被拦截
registration.addPathPatterns("/**");
//添加不拦截路径
registration.excludePathPatterns("/**/*.html", "/**/*.js", "/**/*.css");
}
}
过滤器实现
@Component
@WebFilter(urlPatterns="/**", filterName = "requestAttrFilter")
public class RequestAttrFilter implements Filter {
//排除不拦截的url
private static final String[] EXCLUDE_PATH_PATTERNS = { "/user/get1", "/dept/get1"};
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
StringBuffer requestURL = req.getRequestURL();
String uri = req.getRequestURI();
//对一些url不拦截
if (Arrays.asList(EXCLUDE_PATH_PATTERNS).contains(uri)) {
chain.doFilter(request, response);
}
request.setAttribute("data", "request中放的数据");
if (true) {
//满足要求放行
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}
request.setAttribute("myApplicationName", "fsx-application");
request.getRequestDispatcher("/index").forward(request, response);
从session获取之前设置到session中的数据
用法和@RequestAttribute一样
将model设置到session中去,供后续访问请求的模型属性的名称或模型属性的类型
@SessionAttributes("user")
public class LoginController {
//我们定义了一个名为“User”的model并把它存储在Session中
@ModelAttribute("user")
public User setUpUserForm() {
return new User();
}
}
axios.get('http://127.0.0.1:8080/dept/get6')
.then(function (response) {
_this.info1 = response.data.data;
})
.catch(function (error) {
console.log(error);
});
@GetMapping("/get6")
public ApiResult get6(@RequestHeader String accept, @RequestHeader(value = "connection") String conn) {
log.info("客户端接收内容类型:{}, 是否持久连接:{}", accept, conn);
return ApiResult.ok(accept);
}
返回给前端状态码
有下面三种用法:
axios.get('http://127.0.0.1:8080/dept/get7',{
params: {
name: '安卓开发',
info: '安卓开发'
}
})
.then(function (response) {
_this.info1 = response.data.data;
})
.catch(function (error) {
_this.info1 = error;
});
@GetMapping("/get7")
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
public ApiResult get7(String name, String info) {
return ApiResult.ok(name);
}
@ControllerAdvice
@Slf4j
@ResponseStatus
public class GlobalExceptionHandler {
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public ApiResult customException(Exception e) {
log.info("优先级更高的异常", e);
return ApiResult.ok();
}
}
@GetMapping("/get7")
public ApiResult get7(String name, String info) {
int a = 1/0;
return ApiResult.ok(name);
}
@ResponseStatus(HttpStatus.OK)
public class DeptException extends RuntimeException {
public DeptException() {
super();
}
public DeptException(String message) {
super(message);
}
}
@GetMapping("/get7")
public ApiResult get7(String name, String info) {
throw new DeptException("dept异常");
}