SpringMVC学习

概论

Spring MVC是一个Java框架,用于构建Web应用程序。它遵循Model-View-Controller设计模式。它实现了核心Spring框架的所有基本功能,例如控制反转,依赖注入。

Spring MVC通过 DispatcherServlet 提供了一种优雅的解决方案,可以在Spring框架中使用MVC。在这里, DispatcherServlet 是一个类,用于接收传入的请求并将其映射到正确的资源,例如控制器,模型和视图。

Spring MVC 的实现步骤

  1. 创建 web 应用。
  2. 加入 web 依赖,如 Spring-webmvc 和 servlet 依赖。
  3. 声明 springmvc 核心对象 DispatcherServlet
  4. 创建一个 jsp,发起请求。
  5. 创建一个普通类,作为控制器使用,代替之前的 servlet。
  6. 创建显示处理结果的 jsp 页面。
  7. 创建 springmvc 的配置文件。

通过以上步骤,可以实现一个简单的 Spring MVC 应用,并利用其强大的功能和灵活的架构进行 web 开发。流程如下图所示:

请添加图片描述

Spring MVC Framework的优点

让我们看看Spring MVC Framework的一些优点:

分离角色-Spring MVC分离每个角色,其中可以由专门的对象来实现模型对象,控制器,命令对象,视图解析器,DispatcherServlet,验证器等。

轻量-它使用轻巧的servlet容器来开发和部署您的应用程序。

强大的配置-它为框架和应用程序类提供了可靠的配置,其中包括跨上下文的轻松引用,例如从Web控制器到业务对象和验证器。

快速开发-Spring MVC促进了快速并行的开发。

可重复使用的业务代码-无需创建新对象,它使我们可以使用现有业务对象。

易于测试-在Spring中,通常我们创建JavaBeans类,使您可以使用setter方法注入测试数据。

灵活的映射-它提供了可轻松重定向页面的特定注释。

代码实现

在这之前写一个连接数据库的bean,这个在MySQL篇写到,可在主页寻找知识。

引入依赖

<!--引入了MVC的依赖 包含了IoC的内容-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

配置类application.yaml

server:
  # 配置tomcat的端口号 默认是8080
  port: 8001
  # 配置项目的web路径
  servlet:
    context-path: / #名字,默认/
spring:
  application:
    # 给项目起了一个名字
    name: boot-mvc
  mvc:
    view:
      suffix: .html  #因为我的前端用html演示效果,在下面书写controller里a不用加后缀
      prefix: / #controller里a是根的a.html

书写一个简单的前端界面

请添加图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
我是首页
<a href="/first/a">访问FirstController的a方法</a>
<a href="first/b">访问FirstController的b方法</a>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>a.html</h3>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>b.html</h3>
</body>
</html>

页面跳转

书写controller(入门)
import jakarta.servlet.annotation.WebServlet;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Slf4j
// 类似于servlet
// new对象
@Controller
// 设置web路径
// @WebServlet("/first")
@RequestMapping(value = "/first")
public class FirstController {

    // http://localhost:8001/first/a
    @RequestMapping(value = "/a")
    public String a(){
        log.info("用户访问了FirstController的a方法!");
        // 响应 要跳转到哪里去 a
        return "a";
    }
    // 缩写形式
    @RequestMapping("/b")
    public String b(){
        log.info("用户访问了FirstController的b方法!");
        // 响应 要跳转到哪里去 b
        return "b";
    }
}
书写启动类并启动
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BootMVCApplication {
    public static void main(String[] args) {
        SpringApplication.run(BootMVCApplication.class,args);
    }
}
在浏览器输入路径访问,并且点击跳转

请添加图片描述

传参操作

书写controller
import com.jiazhong.boot.commons.bean.Users;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
// 参数传递问题
@Slf4j
@Controller
@RequestMapping("/second")
public class SecondController {

    @RequestMapping("/a")
    public String a(String name) {
        log.info("用户访问了SecondController的a方法!");
        log.info("name:{}", name);
        return "a";
    }
}
启动后浏览器访问

请添加图片描述

@RequestMapping("/b")
public String b(@RequestParam(name = "page", defaultValue = "1") int p) { //如果没传值,默认为1
    log.info("用户访问了SecondController的b方法!");
    log.info("页码:{}", p);
    return "a";
}

请添加图片描述

@RequestMapping("/c")
public String c(String name, int age, char gender) {
    log.info("用户访问了SecondController的c方法!");
    log.info("name:{},age:{},gender:{}", name, age, gender);
    return "a";
}

请添加图片描述

@RequestMapping("/d")
public String d1(Users user) {
    log.info("用户访问了SecondController的d1方法!");
    log.info("user:{}", user);
    return "a";
}

请添加图片描述

获取值和重定向

import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.IOException;
import java.io.PrintWriter;

@Slf4j
@Controller
@RequestMapping("/third")
public class ThirdController {

    @RequestMapping("/a") //重定向
    public String a() {
        log.info("用户访问了ThirdController的a方法!");
        return "redirect:/a.html";
    }

    @RequestMapping("/b") //获取值
    public String b(HttpServletRequest request, HttpServletResponse response) throws IOException {
        HttpSession session = request.getSession();
        ServletContext application = session.getServletContext();
        PrintWriter out = response.getWriter();
        log.info("request:{}", request);
        log.info("response:{}", response);
        log.info("session:{}", session);
        log.info("application:{}", application);
        log.info("out:{}", out);
        log.info("用户访问了ThirdController的b方法!");
        return "redirect:/a.html";
    }
}

注意:post、put、delete请求要用Apipost(一个测试的软件)测

数据返回

import com.jiazhong.boot.commons.bean.Users;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Controller
@RequestMapping("/fourth")
public class FourthController {


    @RequestMapping("/a")
    public void a(HttpServletResponse response) throws IOException {
        log.info("用户访问了FourthController的a方法");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("Hello,world!");
    }

    @RequestMapping("/b")
    @ResponseBody  // 告诉服务器,这里的返回结果不再是页面跳转,而是数据的输出
    public String b() {
        log.info("用户访问了FourthController的b方法");
        return "Hello,world!";
    }

    @RequestMapping(value = "/c", produces = {"application/json;charset=utf-8"})
    @ResponseBody
    public Users c() { //返回对象
        log.info("用户访问了FourthController的c方法");
        Users users = new Users();
        users.setId(1);
        users.setName("张三");
        users.setAge(29);
        users.setGender('男');
        return users;
    }

    @RequestMapping("/d")
    @ResponseBody
    public List<Users> d() { //返回集合
        log.info("用户访问了FourthController的d方法");
        Users u1 = new Users(1, "张三", 23, '男');
        Users u2 = new Users(2, "李四", 21, '女');
        Users u3 = new Users(3, "王五", 26, '男');
        Users u4 = new Users(4, "马六", 25, '男');
        List<Users> list = Arrays.asList(u1, u2, u3, u4);
        return list;
    }
}

指定返回类型(Get、Post、Put、Delete)

import com.jiazhong.boot.commons.bean.Users;
import com.jiazhong.boot.commons.util.JsonResult;
import com.jiazhong.boot.commons.util.ResultTool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
// 当前类的所有请求,都允许其他项目访问
@CrossOrigin
@Slf4j
// @Controller+@ResponseBody
@RestController
@RequestMapping("/fifth")
public class FifthController {

    // @RequestMapping(value = "/a", method = RequestMethod.GET)
    // @GetMapping("/a")
    @GetMapping
    public JsonResult a() {
        log.info("用户访问了FifthController的a方法");
        return ResultTool.success("用户访问了FifthController的a方法");
    }

    @PostMapping
    public JsonResult b(String name, int age) {
        log.info("用户访问了FifthController的b方法");
        log.info("name:{},age:{}", name, age);
        return ResultTool.success("用户访问了FifthController的b方法");
    }

    @PostMapping("/c1")
    public JsonResult c1(Users user) {
        log.info("用户访问了FifthController的c1方法");
        log.info("user:{}", user);
        return ResultTool.success("用户访问了FifthController的c1方法");
    }

    @PostMapping("/c2")
    public JsonResult c2(@RequestBody Users user) {
        log.info("用户访问了FifthController的c2方法");
        log.info("user:{}", user);
        return ResultTool.success("用户访问了FifthController的c2方法");
    }

    @PutMapping("/d")
    public JsonResult d(Users user) {
        log.info("用户访问了FifthController的d方法");
        log.info("user:{}", user);
        return ResultTool.success("用户访问了FifthController的d方法");
    }
    @DeleteMapping("/e")
    public JsonResult e(Users user){
        log.info("用户访问了FifthController的e方法");
        log.info("user:{}", user);
        return ResultTool.success("用户访问了FifthController的e方法");
    }
}

另外的传参方式

import com.jiazhong.boot.commons.util.JsonResult;
import com.jiazhong.boot.commons.util.ResultTool;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

// Restful风格
@RestController
@RequestMapping("/sixth")
public class SixthController {

    // http://localhost:8001/sixth
    @GetMapping
    public JsonResult a() {
        return ResultTool.success("a");
    }

    // 过去:http://localhost:8001/sixth/b?name=admin
    // 现在:http://localhost:8001/sixth/b/admin
    @GetMapping("/b/{name}")
    public JsonResult b(@PathVariable("name") String name) {
        return ResultTool.success(name);
    }

    @GetMapping("/c/{name}/{age}")
    public JsonResult c(@PathVariable("name") String name, @PathVariable("age") int age) {
        return ResultTool.success(name + ".." + age);
    }
    // 不在另外演示post、put以及delete
}

获取请求头(header)

import com.jiazhong.boot.commons.util.JsonResult;
import com.jiazhong.boot.commons.util.ResultTool;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@CrossOrigin
@Slf4j
@RestController
@RequestMapping("/seventh")
public class SeventhController {

    @GetMapping
    public JsonResult execute(HttpServletRequest request) {
        String token = request.getHeader("token");
        log.info("token:{}", token);
        return ResultTool.success(token);
    }
}

前后端分离实现

用HBuilderX或者WebStorm来书写前端代码

前端代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>
<div id="app">
    <button @click="funA">调用a方法</button>
    <hr />
    <input v-model="name" />
    <input v-model="age" />
    <button @click="funB">调用b方法</button>
    <hr />
    <input v-model="name" />
    <input v-model="age" />
    <button @click="funC">调用c方法</button>
    <hr />
    <input v-model="name" />
    <input v-model="age" />
    <button @click="funD">调用d方法</button>
    <hr />
    <button @click="funE">调用e方法</button>
</div>
</body>
</html>
<script src="../js/vue.min.js"></script>
<script src="../js/axios.min.js"></script>
<script>
    new Vue({
        el: '#app',
        data() {
            return {
                name: '',
                age: ''
            }
        },
        methods: {
            funA() {
                axios({
                    method: "get",
                    url: "http://localhost:8001/fifth"
                }).then(resp => {
                    console.log(resp.data)
                })
            },
            funB() {
                let data = new URLSearchParams()
                data.append('name', this.name)
                data.append('age', this.age)
                axios({
                    method: 'post',
                    url: "http://localhost:8001/fifth",
                    data: data
                }).then(resp => {
                    console.log(resp.data)
                })
            },
            funC() {
                let data = new URLSearchParams()
                data.append('name', this.name)
                data.append('age', this.age)
                axios({
                    method: 'put',
                    url: "http://localhost:8001/fifth/d",
                    data: data
                }).then(resp => {
                    console.log(resp.data)
                })
            },
            funD() {
                axios({
                    method: 'delete',
                    url: "http://localhost:8001/fifth/e",
                    params: {
                        name: this.name,
                        age: this.age
                    }
                }).then(resp => {
                    console.log(resp.data)
                })
            },
            funE(){
                axios({
                    method:'get',
                    url:'http://localhost:8001/seventh',
                    headers:{
                        token:'egrdjksgu21ekjdsfksggfjkv'
                    }
                }).then(resp=>{
                    console.log(resp.data)
                })
            }
        }
    })
</script>

允许跨域方式

1.在controller里加注解@Controller(局部)

当前类的所有请求,都允许其他项目方法

2.书写一个跨域配置类config(全局)

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 所有接口都允许跨域
                .allowedOriginPatterns("*") // 允许所有域名(SpringBoot 2.4+ 用这个)
                .allowCredentials(true) // 允许携带Cookie
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的请求方式
                .maxAge(3600); // 预检请求有效期(秒)
    }
}

3.注册一个CorsFilter 过滤器(全局)

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsFilterConfig {
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOriginPattern("*"); // 允许所有域名
        config.setAllowCredentials(true);
        config.addAllowedMethod("*"); // 允许所有请求方式
        config.addAllowedHeader("*"); // 允许所有请求头

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config); // 匹配所有接口
        return new CorsFilter(source);
    }
}

4.网关统一配置application.yaml(微服务场景)

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowed-origin-patterns: "*"
            allowed-headers: "*"
            allowed-methods: "*"
            allow-credentials: true

MVC与拦截器实现

拦截器实现步骤

1.实现一个方法HandlerInterceptor
2.重写里面的方法(一去二回)
3.注册拦截器(config)

书写controller

import com.jiazhong.boot.commons.util.JsonResult;
import com.jiazhong.boot.commons.util.ResultTool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/first")
public class FirstController {
    @GetMapping("/a")
    public JsonResult a(){
        log.info("This is FirstController a method");
        return ResultTool.success("This is FirstController a method");
    }
    @GetMapping("/b")
    public JsonResult b(){
        log.info("This is FirstController b method");
        return ResultTool.success("This is FirstController b method");
    }
}

书写拦截器

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Slf4j
@Component
public class FirstInterceptor implements HandlerInterceptor {
    //去的方法 过滤的方法
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("This is FirstInterceptor preHandle");
        return true;//true表示放行,false表示拦截
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("This is FirstInterceptor postHandle");//回的
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("This is FirstInterceptor afterCompletion");//回的
    }
}
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Slf4j
@Component
public class SecondInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("This is SecondInterceptor preHandle");
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("This is SecondInterceptor postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("This is SecondInterceptor afterCompletion");
    }
}
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Component
@Slf4j
public class ThirdInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("This is ThirdInterceptor preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("This is ThirdInterceptor postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("This is ThirdInterceptor afterCompletion");
    }
}
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Component
@Slf4j
public class FourthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("This is FourthInterceptor preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("This is FourthInterceptor postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("This is FourthInterceptor afterCompletion");
    }
}

注册拦截器

import com.jiazhong.spring.boot.mvc.interceptor.interceptor.FirstInterceptor;
import com.jiazhong.spring.boot.mvc.interceptor.interceptor.FourthInterceptor;
import com.jiazhong.spring.boot.mvc.interceptor.interceptor.SecondInterceptor;
import com.jiazhong.spring.boot.mvc.interceptor.interceptor.ThirdInterceptor;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

// 对MVC进行配置的一个Configuration
@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
    @Resource
    private FirstInterceptor firstInterceptor;
    @Resource
    private SecondInterceptor secondInterceptor;
    @Resource
    private ThirdInterceptor thirdInterceptor;
    @Resource
    private FourthInterceptor fourthInterceptor;

    // 注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册了拦截器并设置对哪些请求进行拦截
        registry.addInterceptor(firstInterceptor)
                .addPathPatterns("/first/**")
                .excludePathPatterns("/first/a").order(1);

        registry.addInterceptor(secondInterceptor)
                .addPathPatterns("/**").order(7);

        registry.addInterceptor(thirdInterceptor)
                .addPathPatterns("/**").order(98);

        registry.addInterceptor(fourthInterceptor)
                .addPathPatterns("/**").order(3);
    }
}
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐