Spring MVC的入门级介绍

分在学习Spring的过程中,原本想阶段性的把Spring MVC框架做一个总结,但是查阅了相关资料发现这个框架还是很庞大的,有一些框架内容自己还没有用到,做全面的总结也没什么意义,所以就基于目前自己点亮的框架功能,做一个入门级的总结吧。赶紧泰勒一下,做个巩固。请各位批评指正。

什么是Spring MVC

首先还是明确研究对象,Spring MVC本质是一个web前端的应用开发框架,所谓框架首先一定是一个理念(MVC的设计范式)并由此配套的运行流程和抽象概念(控制器、模型和视图),然后就是能给这套理念落地的东西包括给你预先定义的项目架构,Springframework中强大的配置库(尤其是注解库)来支持这套体系从理念变成能落地的解决方案,同时除了Spring体系的支持以外,像lombok、Thymeleaf这些第三方框架的支持,使得Spring MVC更加的强大。下面就从Spring MVC的理念和落地展开说下。

Spring MVC的设计理念

顾名思义,Spring MVC的设计理念就是MVC的设计理念,只要你愿意你也可以做一个“张三 MVC”,“李四 MVC”,Spring MVC就是Spring这个大家庭做的MVC解决方案。

MVC的设计理念

MVC的设计理念追求的是低耦合,这也是目前大部分企业级应用设计共同遵循的原则之一(对于设计模式感兴趣的朋友可以看看《设计模式》这本书)。MVC通过将业务逻辑、数据、显示分离的方法来组织代码,最主要的目的是降低视图和业务逻辑代码之间的双向耦合,同时对于解耦的概念也比较清晰的定义了职责。MVC主要解耦出来了三个核心概念:

  • 模型(Model):定义应用的数据结构
  • 视图(View):定义面向用户的展示模板
  • 控制器(Controller):接收用户输入,更新模型或直接更新视图。

(这个MVC的核心理念,Spring MVC的模型、视图和控制器在功能上做了一定的延展)

MVC的运作流程如下:

这个是MDN官方对于MVC框架运作的描述,可以看到主要有两条运作路径:

  • 用户操作View-->View将操作指令传递给Controller-->Controller直接更新View
  • 用户操作View-->View将操作指令传递给Controller-->Controller基于Model的数据结构改变数据内容-->Model向View反馈更新后的数据

注意MVC是面向所有软件开发的设计理念,不仅仅是web开发,所以这个指令也是个抽象概念,不仅仅是HTTP。

Spring MVC基于MVC在框架上做了哪一些调整(或者具像化)

首先,Spring是面向Web开发的,所以Spring MVC的框架基于Web开发的特点做了一定程度的优化。在模型、视图和控制器这三个概念的功能上有了一些扩充:

  • Spring MVC的模型:应用程序的数据,这里的模型我理解就不是数据结构了,而是提供给视图的数据
  • Spring MVC的视图:定义面向用户的展示模板
  • Spring MVC的控制器:1、接受并处理过的请求,但是这里控制器接受的请求是经过前端控制器DispatcherServlet处理过的请求;2、向Model对象添加属性,以供视图调用

这里还有一个概念就是前端控制器DispatcherServlet负责处理请求后给到控制器(基于@RequestMapping标记的路径来分配),但是Spring MVC已经让我们对这个步骤无感了,先不说了。

控制器有了向模型对象添加属性的功能,这使得对于不同视图的控制器能够定制化不同的模型属性,同时还提供了@SessionAttributes注解标注能够跨多个请求的模型属性。

运作的流程如下:

其中Front controller是应用请求的核心交互组件,model由Controller创建并发起传输。所以MVC的两条路径就变成:

  • 用户发起请求-->Front controller分发请求到不同Controller-->Controller处理请求并创建模型-->Controller向不同视图分发处理-->Front controller分发-->views渲染后通过Front controller向浏览器返回响应
  • 第二条路径与第一条类似,只不过不带模型传输

Spring MVC的落地工具

有了概念,就要有落地的工具,Spring MVC基于Spring framework和第三方生态的强大能力,使得其成为当前最易操作的web MVC框架之一(当然也把一些以往web开发的重要概念(比如servlet)弄的无感了,所以我觉得Spring MVC是一个好的web应用开发框架,但是如果是作为学习web开发的框架就有点太抽象了)。因为这个体系太大了,很多功能现在还没有遇到,所以先总结目前遇到过的内容。

Spring MVC视图模块

视图模板库 

这里要说的就是Spring支持的大量视图模板库,其中支持Spring Boot自动配置功能的模板库包括:

模板Spring Boot starter依赖
FreeMarkerspring-boot-starter-freemarker
Groovy Templatesspring-boot-starter-groovy-templates
JavaServer Pages(JSP)
Mustachespring-boot-starter-mustache
Thymeleafspring-boot-starter-Thymeleaf

只需要将选中的视图模板在pom.xml配置中设置就可以引用了。

视图的使用不同的模板库不一样,前期使用主要以Thymeleaf为主,后续会专门做一个总结,这里就不涉及了。

Spring MVC控制器模块

控制器的注解

控制器的注解前期使用的主要有4个:

  • @Slf4j:这是Lombok提供的注解,在编译期,它会在这个类中自动生成一个SLF4J Logger的静态属性,便于后续在应用部署时使用各种日志框架;
  • @Controller:Spring会将被Controller注解的类识别为控制器;
  • @RequestMapping:注解控制器所处理的请求路径和类型
  • @SessionAttributes:可以将该控制器的相关模型属性加入到会话中供其他请求调用

请求的处理

对于GET、POST、PUT、DELETE、PATCH五种常见的web请求都有相应的注解用来标注处理的方法:

注解描述
@GetMapping处理HTTP GET请求
@PostMapping处理HTTP POST请求
@PutMapping处理HTTP PUT请求
@DeleteMapping处理HTTP DELETE请求
@PatchMapping处理HTTP PATCH请求

@Slf4j
@Controller
@SessionAttributes({"tacoOrder","test"})
@RequestMapping("/orders")
public class OrderController {
    @GetMapping("/current")
    public String orderForm(){
        return "orderForm";
    }

    @PostMapping
    public String processOrder(@Valid TacoOrder tacoOrder, Errors errors,SessionStatus sessionstatus){
        if (errors.hasErrors()) {
            return "OrderForm";
        }
        log.info("Order submitted:{}", tacoOrder);
        sessionstatus.setComplete();
        return "redirect:/";
    }
}

比如《Spring in action》中Taco cloud中OrderController的例子,这里@GetMapping(“/current”)定义了要处理来自“/orders/current”的HTTP GET指令,映射的方法就是返回一个视图名称的字符串(Spring会将其映射到对应的视图),@PostMapping就是定义了要处理来自“/orders”的HTTP POST指令,这里的映射方法接收了来自视图输入域的tacoOrder,校验结果errors和会话状态sessionstatus,最后的return也指明了后续的路径。

模型属性的添加

通过@ModelAttribute注解向模型中添加属性,只有添加的属性才能在视图间赋值和传输。


@Slf4j
@Controller
@RequestMapping("/design")
@SessionAttributes(value={"tacoOrder","test"})

public class DesignTacoController {
    @ModelAttribute
    public void addIngredientsToModel(Model model){
        List<Ingredient> Ingredients = Arrays.asList(
            new Ingredient("FLTO", "Flour Tortilla", Type.WRAP),
            new Ingredient("COTO", "Corn Tortilla", Type.WRAP),
            new Ingredient("GRBF", "Ground Beef", Type.PROTEIN),
            new Ingredient("CARN", "Carnitas", Type.PROTEIN),
            new Ingredient("TMTO", "Diced Tomato", Type.VEGGIE),
            new Ingredient("LETC", "Lettuce", Type.VEGGIE),
            new Ingredient("CHED", "Cheddar", Type.CHEESE),
            new Ingredient("JACK", "Monterry Jack", Type.CHEESE),
            new Ingredient("SLSA", "Salsa", Type.SAUCE),
            new Ingredient("SRCR", "Sour Cream", Type.SAUCE)
        );

        Type[] types = Ingredient.Type.values();
        for (Type type : types) {
            model.addAttribute(type.toString().toLowerCase(), filterByType(Ingredients,type));
        }
    
    }

    @ModelAttribute(name="tacoOrder")
    public TacoOrder order(){
        return new TacoOrder();
    }

    @ModelAttribute(name="taco")
    public Taco taco(){
        return new Taco();
    }

    @ModelAttribute(name="test")
    public Test test(){
        return new Test();
    }

    @GetMapping
    public String showDesignForm(){
        return "design";
    }

    private Iterable<Ingredient> filterByType(List<Ingredient>ingredients, Type type){
        return ingredients.stream().filter(x->x.getType().equals(type)).collect(Collectors.toList());
    }

    @PostMapping
    public String processTaco(@Valid Taco taco, Errors errors, @ModelAttribute TacoOrder tacoOrder, @ModelAttribute Test test){
        if (errors.hasErrors()) {
            return "design";
        }
        tacoOrder.addTaco(taco);
        log.info("Processing taco: {}",taco);
        
        test.setStr1("second");

        return "redirect:/orders/current";
    }
}

 可以发现,添加model属性有两种方式:

  • 被@ModelAttribute注解的方法直接返回的对象
  • 通过model.addAttribute添加的对象

以上是目前我目前点亮的核心功能,其他内容等后续再总结吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值