Controller控制器

目录

概述

配置视图解析器和控制器

@RequestMapping

@RequestParam和@RequestHeader

@CookieValue和@SessionAttrbutie

重定向和请求转发

Bean的Web作用域


概述

Spring Web 模型-视图-控制(MVC)框架是围绕 DispatcherServlet 设计的,DispatcherServlet 用来处理所有的 HTTP 请求和响应。Spring Web MVC DispatcherServlet 的请求处理的工作流程

  • 收到一个 HTTP 请求后,DispatcherServlet 根据 HandlerMapping 来选择并且调用适当的控制器

  • 控制器接受请求,并基于使用的 GET 或 POST 方法来调用适当的 service 方法。Service 方法将设置基于定义的业务逻辑的模型数据,并返回视图名称到 DispatcherServlet 中。

  • DispatcherServlet 会从 ViewResolver 获取帮助,为请求检取定义视图。

  • 一旦确定视图,DispatcherServlet 将把模型数据传递给视图,最后呈现在浏览器中。

 当一个请求经过`DispatcherServlet`之后,会先走`HandlerMapping`,它会将请求映射为`HandlerExecutionChain`,依次经过`HandlerInterceptor`有点类似于javaweb的过滤器,在SpringMVC中是拦截器,然后再交给`HandlerAdapter`,根据请求的路径选择合适的控制器进行处理,控制器处理完成之后,会返回一个`ModelAndView`对象,包括数据模型和视图,通俗的讲就是页面中数据和页面本身(只包含视图名称),返回`ModelAndView`之后,会交给`ViewResolver`(视图解析器)进行处理,视图解析器会对整个视图页面进行解析,SpringMVC自带的视图解析器只适用于JSP页面,可以用Thymeleaf作为新的视图解析器,这样就可以根据给定的视图名称,直接读取HTML编写的页面,解析为一个真正的View。解析完成后,就需要将页面中的数据全部渲染到View中,最后返回给`DispatcherServlet`一个包含所有数据的成形页面,再响应给浏览器,完成整个过程。

配置视图解析器和控制器

使用Thymeleaf为我们提供的视图解析器

导入依赖

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.12.RELEASE</version>
</dependency>

配置视图解析器只需要将对应的`ViewResolver`注册为Bean

@ComponentScan("com.example.controller")
@Configuration
@EnableWebMvc
public class WebConfiguration {

  //我们需要使用ThymeleafViewResolver作为视图解析器,并解析我们的HTML页面
    @Bean
    public ThymeleafViewResolver thymeleafViewResolver(@Autowired SpringTemplateEngine springTemplateEngine){
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setOrder(1);   //可以存在多个视图解析器,并且可以为他们设定解析顺序
        resolver.setCharacterEncoding("UTF-8");   //编码格式是重中之重
        resolver.setTemplateEngine(springTemplateEngine);   //和之前JavaWeb阶段一样,需要使用模板引擎进行解析,所以这里也需要设定一下模板引擎
        return resolver;
    }
  
  	//配置模板解析器
  	@Bean
    public SpringResourceTemplateResolver templateResolver(){
        SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
        resolver.setSuffix(".html");   //需要解析的后缀名称
        resolver.setPrefix("/");   //需要解析的HTML页面文件存放的位置
        return resolver;
    }
  	
  	//配置模板引擎Bean
  	@Bean
    public SpringTemplateEngine springTemplateEngine(@Autowired ITemplateResolver resolver){
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(resolver);   //模板解析器,默认即可
        return engine;
    }
}

创建一个Controller,只需在一个类上添加一个`@Controller`注解即可,它会被Spring扫描并自动注册为Controller类型的Bean,然后只需要在类中编写方法用于处理对应地址的请求即可,配置类中要加个包扫描

@Controller   //直接添加注解即可
public class MainController {

    @RequestMapping("/index")   //直接填写访问路径
    public ModelAndView index(){
        return new ModelAndView("index");  //返回ModelAndView对象,这里填入了视图的名称
      	//返回后会经过视图解析器进行处理
    }
}

页面中的数据我们可以直接向Model进行提供

@RequestMapping(value = "/index")
public ModelAndView index(){
    ModelAndView modelAndView = new ModelAndView("index");
    modelAndView.getModel().put("name", "啊这");
    return modelAndView;
}

Thymeleaf收到传递数据就能进行解析

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    HelloWorld!
    <div th:text="${name}"></div>
</body>
</html>

仅仅是传递一个页面不需要任何的附加属性,可以直接返回View名称,SpringMVC会将其自动包装为ModelAndView对象

@RequestMapping(value = "/index")
public String index(){
    return "index";
}

单独添加一个Model作为形参进行设置,SpringMVC会自动帮助我们传递实例对象

@RequestMapping(value = "/index")
public String index(Model model){  //这里不仅仅可以是Model,还可以是Map、ModelMap
    model.addAttribute("name", "yyds");
    return "index";
}

页面中可能还会包含一些静态资源,比如js、css,因此还需要配置一下,让静态资源通过Tomcat提供的默认Servlet进行解析,需要让配置类实现一下`WebMvcConfigurer`接口并添加'@EnableWebMvc',这样在Web应用程序启动时,会根据我们重写方法里面的内容进行进一步的配置

@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();   //开启默认的Servlet
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/static/**").addResourceLocations("/WEB-INF/static/");   
  	//配置静态资源的访问路径
}

@RequestMapping

我们需要完整地编写一个Servlet来处理请求,而现在我们只需要在控制器的方法上添加一个`@RequestMapping`即可实现,此注解就是将请求和处理请求的方法建立一个映射关系,当收到请求时就可以根据映射关系调用对应的请求处理方法

源码展示

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}

path属性(等价于value),它决定了当前方法处理的请求路径,注意路径必须全局唯一,任何路径只能有一个方法进行处理,它是一个数组,也就是说此方法不仅仅可以只用于处理某一个请求路径,也可以使用此方法处理多个请求路径

@RequestMapping({"/index", "/test"})
public ModelAndView index(){
    return new ModelAndView("index");
}

`@RequestMapping`添加到类名上,表示为此类中的所有请求映射添加一个路径前缀

@Controller
@RequestMapping("/yyds")
public class MainController {

    @RequestMapping({"/index", "/test"})
    public ModelAndView index(){
        return new ModelAndView("index");
    }
}

路径还支持使用通配符进行匹配

* ?:表示任意一个字符,比如`@RequestMapping("/index/x?")`可以匹配/index/xa、/index/xb等等。

* *:表示任意0-n个字符,比如`@RequestMapping("/index/*")`可以匹配/index/lbwnb、/index/yyds等。

* **:表示当前目录或基于当前目录的多级目录,比如`@RequestMapping("/index/**")`可以匹配/index、/index/xxx等。

method属性 可以限定请求方式

@RequestMapping(value = "/index", method = RequestMethod.POST)
public ModelAndView index(){
    return new ModelAndView("index");
}

也可以使用衍生注解直接设定为指定类型的请求映射

这里使用了`@PostMapping`直接指定为POST请求类型的请求映射,同样的,还有`@GetMapping`可以直接指定为GET请求方式

@PostMapping(value = "/index")
public ModelAndView index(){
    return new ModelAndView("index");
}

使用`params`属性来指定请求必须携带哪些请求参数

@RequestMapping(value = "/index", params = {"username", "password"})
public ModelAndView index(){
    return new ModelAndView("index");
}

还支持表达式

@RequestMapping(value = "/index", params = {"!username", "password"})

public ModelAndView index(){

    return new ModelAndView("index");

}

@RequestMapping(value = "/index", params = {"username!=test", "password==123"})

public ModelAndView index(){

    return new ModelAndView("index");

}

`header`属性用法与`params`一致,但是它要求的是请求头中需要携带什么内容

@RequestMapping(value = "/index", headers = "!Connection")
public ModelAndView index(){
    return new ModelAndView("index");
}

如果请求头中携带了`Connection`属性,将无法访问

其他两个属性

* consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;

* produces:  指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;

@RequestParam和@RequestHeader

接收请求中的参数

只需要为方法添加一个形式参数,并在形式参数前面添加`@RequestParam`注解

@RequestMapping(value = "/index")

public ModelAndView index(@RequestParam("username") String username){

    System.out.println("接受到请求参数:"+username);

    return new ModelAndView("index");

}

需要在`@RequestParam`中填写参数名称,参数的值会自动传递给形式参数,我们可以直接在方法中使用,注意,如果参数名称与形式参数名称相同,即使不添加`@RequestParam`也能获取到参数值,(推荐添加注解)

一旦添加`@RequestParam`,那么此请求必须携带指定参数,我们也可以将require属性设定为false来将属性设定为非必须

@RequestMapping(value = "/index")

public ModelAndView index(@RequestParam(value = "username", required = false) String username){

    System.out.println("接受到请求参数:"+username);

    return new ModelAndView("index");

}

设定一个默认值,当请求参数缺失时,可以直接使用默认值

@RequestMapping(value = "/index")

public ModelAndView index(@RequestParam(value = "username", required = false, defaultValue = "zzp") String username){

    System.out.println("接受到请求参数:"+username);

    return new ModelAndView("index");

}

如果需要使用Servlet原本的一些类

@RequestMapping(value = "/index")

public ModelAndView index(HttpServletRequest request){

    System.out.println("接受到请求参数:"+request.getParameterMap().keySet());

    return new ModelAndView("index");

}

直接添加`HttpServletRequest`为形式参数即可,SpringMVC会自动传递该请求原本的`HttpServletRequest`对象,同理,我们也可以添加`HttpServletResponse`作为形式参数,甚至可以直接将HttpSession也作为参数传递

还可以直接将请求参数传递给一个实体类,注意必须携带set方法或是构造方法中包含所有参数,请求参数会自动根据类中的字段名称进行匹配

@Data
public class User {
    String username;
    String password;
}
@RequestMapping(value = "/index")
public ModelAndView index(User user){
    System.out.println("获取到cookie值为:"+user);
    return new ModelAndView("index");
}

`@RequestHeader`与`@RequestParam`用法一致,不过它是用于获取请求头参数

@CookieValue和@SessionAttrbutie

通过使用`@CookieValue`注解,我们也可以快速获取请求携带的Cookie信息

@RequestMapping(value = "/index")
public ModelAndView index(HttpServletResponse response,
                          @CookieValue(value = "test", required = false) String test){
    System.out.println("获取到cookie值为:"+test);
    response.addCookie(new Cookie("test", "lbwnb"));
    return new ModelAndView("index");
}

同样的,Session也能使用注解快速获取

@RequestMapping(value = "/index")
public ModelAndView index(@SessionAttribute(value = "test", required = false) String test,
                          HttpSession session){
    session.setAttribute("test", "xxxx");
    System.out.println(test);
    return new ModelAndView("index");
}

重定向和请求转发

只需要在视图名称前面添加一个前缀即可

重定向

@RequestMapping("/index")
public String index(){
    return "redirect:home";
}

@RequestMapping("/home")
public String home(){
    return "home";
}

请求转发

@RequestMapping("/index")
public String index(){
    return "forward:home";
}

@RequestMapping("/home")
public String home(){
    return "home";
}

Bean的Web作用域

SpringMVC中,bean的作用域被继续细分,默认还是单例模式

* request:对于每次HTTP请求,使用request作用域定义的Bean都将产生一个新实例,请求结束后Bean也消失。

* session:对于每一个会话,使用session作用域定义的Bean都将产生一个新实例,会话过期后Bean也消失。

* global session:类似于HTTP Session作用域,它只有对portlet才有意义。对于Servlet的web应用就相当于session

创建一个测试类

public class TestBean {

}

接着将其注册为Bean,注意这里需要添加`@RequestScope`或是`@SessionScope`表示此Bean的Web作用域

@Bean

@RequestScope

public TestBean testBean(){

    return new TestBean();

}

将其自动注入到Controller中

@Controller

public class MainController {

    @Resource

    TestBean bean;

    @RequestMapping(value = "/index")

    public ModelAndView index(){

        System.out.println(bean);

        return new ModelAndView("index");

    }

}

每次发起得到的Bean实例都不同,接着我们将其作用域修改为`@SessionScope`,这样作用域就上升到Session,除非清理浏览器的Cookie,那么都会被认为是同一个会话,只要是同一个会话,那么Bean实例始终不变

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值