一.请求
1.建立连接
① @RestController
@RestController = @Controller + @ResponseBody
@Controller:定义⼀个控制器,Spring 框架启动时加载,把这个对象交给Spring管理,属于Ioc&Di的内容。
@ResponseBody:定义返回的数据格式为⾮视图, 返回⼀个 text/html信息
目前的我们只需要理解必须要加 @RestController 这个注解就可以了,它是我们启动程序必须要加的。
② @RequestMapping使用
1.@RequestMapping 是 Spring Web MVC 应⽤程序中最常被⽤到的注解之⼀,它是⽤来注册接⼝的路由映射的,就是来描述访问路径的,通过这个路径我们就可以访问到这个接口。
2.@RequestMapping 既可修饰类,也可以修饰⽅法,代码案例如下:
@RequestMapping("/user") @RestController public class UserController { @RequestMapping("/sayHi") public String sayHi(){ return "hello,Spring MVC"; } }
③ @RequestMapping是GET还是POST请求
1.我们@RequestMapping默认不写要求是什么请求的话,两个请求都是可以的。
2.如果必须要求指定是啥类型的请求,我们可以根据下面的代码格式写:value是路径,method是请求方式。
@RestController public class UserController { @RequestMapping(value = "/getRequest",method= RequestMethod.POST) public String Hello(){ return "get request..."; } }
3.还有@GetMapping,@PostMapping等一些可以写url路径这些和@RequestMapping用法一样知识指定了请求的方式。
2.请求
①传递参数
@RequestMapping("/m2") public Object method2(String name, String password) { return "接收到参数name:" + name + ", password:" + password; }
注意:
1.前端传递传递参数的时候记得参数名对应。
2.参数类型建议写成包装类,因为包装类可以不接受参数,如果使用java内置数据类型,没有接受到参数就会报错。
②传递对象
1.如果参数⽐较多时, ⽅法声明就需要有很多形参. 并且后续每次新增⼀个参数, 也需要修改⽅法声明. 我们不妨把这些参数封装为⼀个对象.然后前端传递参数的时候也只需要知道对象里面的属性,然后对属性名进行传参就可以了。
//Person这个类的代码就不写了 @RequestMapping("/m3") public Object method3(Person p){ return p.toString(); }
注意:Spring 会根据参数名称⾃动绑定到对象的各个属性上, 如果某个属性未传递, 则赋值为null(基本类型则赋值为默认初识值, ⽐如int类型的属性, 会被赋值为0)。
③后端参数重命名
@RequestMapping("/m4") public Object method_4(@RequestParam("time") String createtime) { return "接收到参数createtime:" + createtime; }
上面代码的意思是:前端传递参数的时候用time,后端使用参数的时候使用createtime;此时前端就不能使用createtime进行传递参数了;这时time也变成了必传的参数。
如果要设置成非必须传的可以看以下代码:
@RequestMapping("/m4") public Object method4(@RequestParam(value = "time", required = false) String createtime) { return "接收到参数createtime:" + createtime; }
④传递数组
@RequestMapping("/m5") public String method5(String[] arrayParam) { return Arrays.toString(arrayParam); }
前端传递参数的时候可以对 arrayParam进行多次赋值。
⑤传递集合@RequestParam(加了这个spring MVC会自动帮我们解析,这个在苍穹外卖出现过,这里必须是非json对象)
集合参数:和数组类似, 同⼀个请求参数名有为多个, 且需要使⽤ @RequestParam 绑定参数关系。代码格式如下:
@RequestMapping("/m6") public String method6(@RequestParam List<String> listParam){ return "size:"+listParam.size() + ",listParam:"+listParam; }
⑥传递json数据
1.接收JSON对象, 需要使⽤ @RequestBody 注解
@RequestMapping(value = "/m7") public Object method7(@RequestBody Person person) { //前端发送json对象过来,被Person接受 return person.toString(); }
2.JSON字符串和Java对象互转
引入依赖:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.5</version> </dependency>
转换的代码:
public class JSONUtils { private static ObjectMapper objectMapper = new ObjectMapper(); public static void main(String[] args) throws JsonProcessingException { Person person = new Person(); person.setId(5); person.setName("zhangsan"); person.setPassword("123456"); //对象转为JSON字符串 String jsonStr = objectMapper.writeValueAsString(person); System.out.println("JSON字符串为:"+jsonStr); //JSON字符串转为对象 Person p = objectMapper.readValue(jsonStr,Person.class); System.out.println("转换的对象id:"+p.getId()+",name:"+p.getName()+",password:"+p.getPassword()); } }
⑦获取URL中参数@PathVariable
需要使用@PathVariable这个注解
@RequestMapping("/m8/{id}/{name}") //如果@PathVariable中写了值那么url中就要对应,然后后端还是使用userName public String method8(@PathVariable Integer id, @PathVariable("name") String userName){ return "解析参数id:"+id+",name:"+userName; }
⑧上传文件
@RequestMapping("/m9") // 这里的@RequestPart相当于重命名,前端传参数的时候用file1后端使用文件的时候用file2 public String getfile(@RequestPart("file1") MultipartFile file2) throws IOException { //获取⽂件名称 String fileName = file2.getOriginalFilename(); //⽂件上传到指定路径,就是上传到服务器中指定的路径 file2.transferTo(new File("D:/temp/" + file2.getOriginalFilename())); return "接收到⽂件名称为: "+fileName; }
⑨获取Cookie/Session(过时了,现在一般使用jwt令牌)主要是学习一下里面比较长的两个参数
设置和获取cookie:
// 设置Cookie @GetMapping("/c1") public Result cookie1(HttpServletResponse response) { response.addCookie(new Cookie(name: "login_username", value: "itheima")); return Result.success(); } // 获取Cookie @GetMapping("/c2") public Result cookie2(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); // 获取所有的Cookie for (Cookie cookie : cookies) { if (cookie.getName().equals("login_username")) { // 输出name为 login_username 的cookie System.out.println("login_username: " + cookie.getValue()); } } return Result.success(); }
HttpServletRequest: 对象代表客⼾端的请求,当客⼾端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象提供的⽅法,可以获得客⼾端请求的所有信息.
HttpServletResponse:对象代表服务器的响应.,HTTP响应的信息都在这个对象中,⽐如向客⼾端发送的数据,响应头,状态码等。通过这个对象提供的⽅法,可以获得服务器响应的所有内容。
设置和获取session:
// 在session中存储数据 @GetMapping("/s1") public Result session1(HttpSession session) { log.info("HttpSession-s1: {}", session.hashCode()); session.setAttribute("loginUser", "tom"); // 在session中存储数据 return Result.success(); } // 从HttpSession中获取数据 @GetMapping("/s2") public Result session2(HttpServletRequest request) { HttpSession session = request.getSession(); log.info("HttpSession-s2: {}", session.hashCode()); Object loginUser = session.getAttribute("loginUser"); // 从session中获取数据 log.info("loginUser: {}", loginUser); return Result.success(loginUser); }
⑩获取Header(这个也不是很实用)
获取Header也是从 HttpServletRequest 中获取:
@RequestMapping("/param10") public String param10(HttpServletRequest request, HttpServletResponse response){ String userAgent = request.getHeader("User-Agent"); return name + ":"+userAgent; }
二.响应
①返回静态页面(只有这个用@Controller,后面的②③都是使用 @RestController,④⑤和方法的返回内容不相关了而是设置http协议里面返回的内容)
我们需要把之前用的 @RestController 换成 @Controller 因为 @RestController = @Controller + @ResponseBody 。@ResponseBody定义返回的数据格式为⾮视图, 返回⼀个 text/html信息,所以我们需要返回页面就用@Controller。
@ResponseBody 既是类注解, ⼜是⽅法注解
如果作⽤在类上,表⽰该类的所有⽅法,返回的都是数据,如果作⽤在⽅法上,表⽰该⽅法返回的是数据。如果⼀个类的⽅法⾥,既有返回数据的,⼜有返回⻚⾯的,就把 @ResponseBody 注解添加到对应的⽅法上即可。
②返回HTML片段
如果返回的是非对象或者非集合,返回的格式为text/html。
③返回json
如果后端返回的是对象或者集合,spring会把返回者转换成json对象。但是如果不是也可以强行转换成json对象。
@RequestMapping(value = "/publish",produces = "application/json") // 添加了这个可把返回的对象强行转换成json格式的 public String publish(@RequestBody MessageInfo messageInfo) { if(!StringUtils.hasLength(messageInfo.getMessage()) || !StringUtils.hasLength(messageInfo.getTo()) || !StringUtils.hasLength(messageInfo.getFrom()) ){ return "{\"ok\" : 0}"; } messageInfoList.add(messageInfo); return "{\"ok\" : 1}"; }
④设置状态码
@RequestMapping(value = "/setStatus")
@ResponseBody
public String setStatus(HttpServletResponse response) {
response.setStatus(401); //设置状态码
return "设置状态码成功";
}
⑤设置其他Header
在原生的@RequestMapping已经存在了许多的Header了,但是是我们有时觉得不都我们可以自己设置Header(其中我用过的参数有:value(URL路径),method(请求的类型),produces(返回的内容类型))。
设置其他Header的话,需要使⽤Spring MVC的内置对象HttpServletResponse 提供的⽅法来进⾏设置。
@RequestMapping(value = "/setHeader") @ResponseBody public String setHeader(HttpServletResponse response) { response.setHeader("MyHeader","MyHeaderValue"); return "设置Header成功"; }
void setHeader(String name, String value) 设置⼀个带有给定的名称和值的 header。如果 name 已经存在,则覆盖旧的值。
三.拦截器
1.定义拦截器
① 实现HandlerInterceptor接⼝,并重写其所有⽅法
@Slf4j @Component // 交给spring的ioc容器管理 public class LoginInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("LoginInterceptor ⽬标⽅法执⾏前执⾏.."); return true; // 这里写逻辑,返回true放行,返回false拦截 } public void postHandle(HttpServletRequest request, HttpServletResponseresponse, Object handler, ModelAndView modelAndView) throws Exception { log.info("LoginInterceptor ⽬标⽅法执⾏后执⾏"); } public void afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("LoginInterceptor 视图渲染完毕后执⾏,最后执⾏"); } }
2.注册配置拦截器
① 实现WebMvcConfigurer接⼝,并重写addInterceptors⽅法:
addPathPatterns:添加拦截的路径
excludePathPatterns:排除要拦截的路径
@Configuration // 交给spring的ioc容器管理 public class WebConfig implements WebMvcConfigurer { //⾃定义的拦截器对象 @Autowired private LoginInterceptor loginInterceptor; public void addInterceptors(InterceptorRegistry registry) { //注册⾃定义拦截器对象 registry.addInterceptor(loginInterceptor) .addPathPatterns("/**");//设置拦截器拦截的请求路径( /** 表⽰拦截所有请求) .excludePathPatterns("/user/login"); // 设置拦截器不拦截的路径 } }
四.全局异常处理
统⼀异常处理使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表⽰控制器通知类, @ExceptionHandler 是异常处理器,两个结合表⽰当出现异常的时候执⾏某个通知,也就是执⾏某个⽅法事件。
@ResponseBody @ControllerAdvice public class ErrorAdvice { @ExceptionHandler(Exception.class) // 这个是接受异常的类型 public Object handler(Exception e) { return Result.fail(e.getMessage()); } @ExceptionHandler(NullPointerException.class) public Object handler(Exception e) { return Result.fail("发⽣NullPointerException:"+e.getMessage()); } @ExceptionHandler(IndexOutOfBoundsException.class) public Object handler(Exception e) { return Result.fail("发⽣ArithmeticException:"+e.getMessage()); } }