Spring MVC

发布于:2025-03-25 ⋅ 阅读:(31) ⋅ 点赞:(0)

一.请求

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());
    }
}