SSM 框架学习: 构建 SpringMVC 表述层框架 Published on May 19, 2024 in 日常 with 0 comment SpringFramework SpringMVC ### 一. SpringMVC 的简介  #### 1.1 介绍 SpringMVC 全称是 Spring Web MVC,它是基于 Servlet API 构建的原始 WEB 框架,一开始就包含在 Spring Framework 中。性能卓越,代码简洁,能和 IoC 容器无缝对接。 (1)简化前端参数据接收(形参列表) (2)简化后端数据响应(返回值) #### 1.2 内部流程和核心组件 (1)DispatcherServlet:处理全部请求,[核心]。 (2)handlerMapping 缓存 handler 方法和地址,需要进行 IoC 配置使其加入 IoC容器方可生效。它内部缓存 handler(controller 方法)和 handler 访问路径数据,被 DispatcherServlet 调用。 (3)handleAdapter 适配器,参数和响应简化。 (4)视图解析器:查找视图页面,简化视图查找。如果是前后端分离的项目,后端只返回 Json 数据,此时就不是必须的。 #### 1.3 快速开始 (1)创建项目并导入以下依赖: ```xml 4.0.0 org.example ssm-springmvc-part 1.0-SNAPSHOT pom spring-mvc-base-01 8 8 UTF-8 org.springframework spring-context 5.3.21 javax.servlet javax.servlet-api 4.0.1 org.springframework spring-webmvc 5.3.21 ``` (2)创建一个子模块,然后使用 JBL 将其转成 Web 工程。 (3)声明一个 Controller 方法,代码如下所示: ```java @Controller public class HelloController { // handler -> springmvc/hello return "hello springmvc" @RequestMapping("springmvc/hello") //对外访问的地址 @ResponseBody // 直接返回字符串给前端 不需要找视图解析器 public String hello(){ System.out.println("hello springmvc"); //返回给前端 return "hello springmvc"; } } ``` (4)编辑配置类: ```java @Configuration @ComponentScan("org.example.controller") public class MvcConfig { @Bean public RequestMappingHandlerMapping handlerMapping(){ return new RequestMappingHandlerMapping(); } @Bean public RequestMappingHandlerAdapter handlerAdapter(){ return new RequestMappingHandlerAdapter(); } } ``` (5)引入 SpringMVC 的初始化配置 ```java /* * 可以被 web 项目加载,初始化 ioc 容器,会设置 dispatchServlet 的地址 * * */ public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class>[] getRootConfigClasses() { return new Class[0]; } // 设置项目对应的配置 @Override protected Class>[] getServletConfigClasses() { return new Class[]{MvcConfig.class}; } // 设置 springmvc 内部自带的 servlet 的访问地址 @Override protected String[] getServletMappings() { return new String[]{"/"}; } } ``` (6)部署,看一下效果,注意这里需要下载一个 Tomcat。由于本地环境是 Java 1.8,所以使用的是 Tomcat 8.x 版本。  ### 二. SpringMVC 接收数据 #### 2.1 访问路径设置 通过 `@RequestMapping` 注解来设置访问路径,它将请求的 URL 和处理请求的方式(handler方法)关联起来,建立映射关系。 (1)精确路径匹配 在` @RequestMapping` 注解指定 URL 地址时,不用任何通配符,按照请求地址进行匹配。 ```java @Controller public class UserController { // 允许多个地址,例如 {"path1", "path2"} @RequestMapping("/user/login") public String login(){ return null; } } ``` (2)模糊路径匹配 支持模糊匹配, * 代表任意一层字符串, 两个 * 代表任意层字符串,如 /user/* 可以指代 /user/a 等。 (3)类和方法上的 @RequestMapping 注解的区别,类上是提取通用的访问体制,方法上是具体的 handler 地址。访问是类地址 + 方法地址。如下所示: ```java @RequestMapping("user") @Controller public class UserController { // 允许多个地址,例如 {"path1", "path2"} @RequestMapping("login") public String login(){ return null; } } ``` (4)请求方式指定 客户端: http (get | post | ..) -> ds -> handler。默认情况,只要地址正确,任何请求方式都可以访问。但是请求方式也是可以指定的,参考代码如下: ```java method = {RequestMethod.Get, RequestMethod.Post} ``` ```java @RequestMapping("user") @Controller public class UserController { @RequestMapping(value = "login", method = RequestMethod.POST) public String login(){ return null; } ``` 如果不符合请求方式,就会出现 405 异常。 (5)进阶注解 `@GetMapping` ,相当于 `@RequestMapping(xxx,method=GET);` `@PostMapping` ,相当于 `@RequestMapping(xxx,method=POST);` 但是,需要注意的是这些注解只能使用在方法上。 #### 2.2 JSON 参数接收 前端传递 Json 数据时,SpringMVC 框架可以使用 `@RequestBody` 注解将其转换为 Java 对象。 (1)定义一个接收 Json 数据的 Java 类,如下: ```java package org.alen.pojo; public class Person { private String name; private int age; private String gender; public String getName() { return name; } public int getAge() { return age; } public String getGender() { return gender; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void setGender(String gender) { this.gender = gender; } } ``` (2) 编写对应的 Controller, 代码如下: ```java @RequestMapping("json") @Controller @ResponseBody public class JsonController { // data 请求体 post 方法 传过来数据 @RequestMapping(value = "data", method = RequestMethod.POST) public String data(@RequestBody Person person){ System.out.println("person info = " + person.toString()); return person.toString(); } } ``` (3)Postman 准备测试数据:  这时会发现,出现了 404 的错误,但是地址并没有错误。这是因为之前配置类的信息并没有涵盖新建的路径,简单修改即可:  然后重新运行项目,再次通过 Postman 测试刚才的地址,然后发现报错信息从 404 变成了 415:  ' 这里的原因是因为 Java 原生的 API 只支持路径参数和 `param` 参数。那么,为了解决这个问题,需要实现下面几个步骤。其一是导入 json 处理的依赖,然后在 `handlerAdapter` 配置 json 转换器。 首先,配置 pom,导入依赖: ```xml com.fasterxml.jackson.core jackson-databind 2.15.0 ``` 然后,在配置类中,添加注解` @EnableWebMvc`,配置转化器。 ```java @EnableWebMvc @Configuration @ComponentScan("org.alen.json") public class MvcConfig { @Bean public RequestMappingHandlerMapping handlerMapping(){ return new RequestMappingHandlerMapping(); } @Bean public RequestMappingHandlerAdapter handlerAdapter(){ return new RequestMappingHandlerAdapter(); } } ``` 最后,再用 Postman 测试一下,效果如下:  #### 2.3 Cookie 数据的接收 可以使用` @CookieValue `注解将 HTTP Cookie 的值绑定到控制器的方法参数。 ```java @Controller @ResponseBody @RequestMapping("cookie") public class CookieController { // 取 @RequestMapping("data") public String data(@CookieValue(value = "cookieName") String value) { System.out.println("value : " + value); return value; } // 存 @GetMapping("save") public String save(HttpServletResponse response) { Cookie cookie = new Cookie("cookieName", "root"); response.addCookie(cookie); return "ok"; } } ``` 实现效果: (1)存 Cookie:  (2)取出指定的 Cookie  #### 2.4 获取请求头 示例代码如下所示: ```java @RequestMapping("header") @Controller @ResponseBody public class HeadController { @RequestMapping("data") public String data(@RequestHeader("Host") String host){ System.out.println("host : " + host); return "host : " + host; } } ``` 根据 URL 访问之后获得请求头中的 Host 数据:  #### 2.5 共享域对象操作 在 JavaWeb 中,共享域指的是在 Servlet 中存储数据,以便在同一个 Web 应用的多个组件中进行共享和访问,常见的有以下四种: (1)ServletContext,可以在整个 Web 应用中共享数据,是最大的共享域,一般用于保存整个应用的全局配置信息和所有用户共享的数据。 (2)HttpSession,对象可以在同一用户发出的多个请求之间共享数据,但是只能在同一个会话中使用,例如用户的登录信息,保持登录状态。 (3)HttpServletRequest,可以在同一个请求的多个处理器方法中共享数据。 (4)PageContext,该对象是在 JSP 页面 Servlet 创建时自动创建的,它可以在 JSP 的各个作用域中共享数据。 ```java @Controller @RequestMapping("share") @ResponseBody public class ShareController { @Autowired private ServletContext servletContext; // 原生 API public void data(HttpServletRequest servletRequest, HttpSession session){ }; // SpringMVC 提供的方法: public void dataOne(Model model){ model.addAttribute("key", "value"); //request 共享域 } public void dataOne(ModelMap modelMap){ modelMap.addAttribute("key", "value"); //request 共享域 } public void dataOne(Map map){ map.put("key", "value"); //request 共享域 } public ModelAndView dataOne(){ ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("key", "value"); modelAndView.setViewName("视图/页面名称"); return modelAndView; } } ``` ### 三. SpringMVC 响应数据 #### 3.1 混合开发模式下快速返回模板视图 (1)准备 JSP 和对应的依赖 修改 pom 文件如下所示: ```xml org.glassfish.web jakarta.servlet.jsp.jstl 2.0.0 ``` (2) 创建一个 JSP 页面,位置在 /WEB-INF/ 下,避免外部直接访问。 ```html <%@ page contentType="text/html;charset=UTF-8" language="java" %> JSP TEST Page ${data} ``` (3)准备配置类: ```java @Configuration @ComponentScan("org.example.controller") @EnableWebMvc public class MvcConfig implements WebMvcConfigurer { // handlerMapping 和 handlerAdapter json 转换器,这些可以不手动添加了,添加 @EnableWebMvc 注解即可 // 配置视图解析器,来指定前后缀 @Override public void configureViewResolvers(ViewResolverRegistry registry) { // 快速添加前后缀 registry.jsp("/WEB-INF/" , ".jsp"); } } ``` (4) 初始化配置类,和前面的步骤一样添加以下代码: ```java public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class>[] getRootConfigClasses() { return new Class[0]; } // 设置项目对应的配置 @Override protected Class>[] getServletConfigClasses() { return new Class[]{MvcConfig.class}; } // 设置 springmvc 内部自带的 servlet 的访问地址 @Override protected String[] getServletMappings() { return new String[]{"/"}; } } ``` (5)准备工作都完成后,编写 controller 文件来绑定 JSP。 ```java @Controller @RequestMapping("jsp") public class JspController { /* * TODO : 快速查找视图 * 1、 方法的返回值类型是 字符串 * 2、 不能添加 @ResponseBody * 3、 返回值对应中间的视图名称即可 */ @GetMapping("index") public String index(HttpServletRequest request){ request.setAttribute("data", "hello jsp"); System.out.println("controller output jsp info"); return "index"; } } } ``` (6)使用 Tomcat 运行一下项目看看效果:  #### 3.2 转发和重定向 在 SpringMVC 中,`Handler` 方法返回值来实现快速转发,使用 `redirect` 和 `forward` 关键字来实现重定向。 (1)转发示例 ```java // 转发 // 方法的返回值写成字符串,不能添加responseBody注解,返回的字符串前要添加 forward:/ 转发地址 @GetMapping("forward") public String forward(){ System.out.println("jspController forward"); return "forward:/jsp/index"; } ``` (2)重定向示例 ```java // 重定向 // 方法的返回值携程字符串,不能添加responseBody注解,返回的字符串前要添加 redirect:/ 重定向地址 @GetMapping("redirect") public String redirect(){ System.out.println("jspController redirect"); return "redirect:http://www.baidu.com"; } ``` #### 3.3 返回 JSON 数据 (1)前置准备,导入 Jackson 依赖 ```xml com.fasterxml.jackson.core jackson-databind 2.15.0 ``` (2)添加 Json 数据转化器,`@EnableWebMvc` (3)准备一个实体类 Pojo,由于每次写实体类的时候都要手动添加若干的 setter 和 getter 方法。这里引入一个 `lombok` 的工具。 ```xml org.projectlombok lombok 1.18.12 ``` 实体类: ```java @Data public class User { private String name; private int age; } ``` (4)定义 JSON Controller ```java @Controller @RequestMapping("json") public class JsonController { @GetMapping("data") @ResponseBody // @ResponseBody 注解用于指示一个方法返回的对象应该直接写入 HTTP 响应体中(而不是渲染成 HTML 视图) public User data(){ User user = new User(); user.setName("Test"); user.setAge(17); return user; // 这里 user 会被 handlerAdapter 转为 json } } ``` (5)延展,如果返回的是 List 类型的数据,参考代码如下所示: ```java @GetMapping("data1") @ResponseBody public List dataList(){ User user = new User(); user.setName("Test tt"); user.setAge(17); List users = new ArrayList<>(); users.add(user); return users; } ``` (6) 结果如下所示:   #### 3.4 返回静态资源 (1)首先准备一张静态图片,放置在 webapp 路径下:  (2)在配置类中,开启静态资源查找 ```java @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } ``` (3)重新测试一下,发现已经可以找到资源了。  ### 四. RESTFul 风格设计 #### 4.1 RESTful 概念 这是一种软件架构风格,用于设计网络 APP 和服务之间的通信。它是一种基于标准 HTTP 方法的简单和轻量通信协议,广泛用于 WEB 服务开发。 #### 4.2 RESTful 风格特点 (1)每个 URI 代表一种资源。 (2)客户端使用 GET、POST、PUT、DELETE 4个表示操作方式的动词对服务资源进行操作,其中 GET 表示用来获取资源,POST 表示更新或新建资源,PUT 用来更新资源,DELETE 表示删除资源。 (3)资源的表现形式是 XML 或者 JSON。 (4)客户端与服务端之间的交互在请求间是无状态的。 #### 4.3 风格案例 (1)数据结构 User ,其中 ID 是唯一标识,name 为用户名, age 为用户年龄。 (2)功能分析: - 用户数据分页展示功能 - 保存用户功能 - 根据用户 ID 查询用户详情 - 根据用户 ID 更新用户数据 - 根据用户 ID 删除用户数据 - 多条件模糊查询 (3)注意: 对于 GET 和 DELETE 方法,参数如果是 ID 标识,使用路径传递参数。如果参数不是 ID,例如范围参数,使用 Param 传参。而对于 POST 和 PUT 方法,都是用请求体传递 JSON。 (4)准备用户的实体类: ```java @Data public class User { private Integer id; private String name; private Integer age; } ``` (5)编写对应的 Controller 实现: ```java @ResponseBody @Controller @RequestMapping("user") public class UserController { // 分页查询 @GetMapping public List page(@RequestParam(required = false, defaultValue = "1") int page, @RequestParam(required = false, defaultValue = "10") int size){ System.out.println("page = " + page + " size = "+ size); return null; } // 用户添加 @PostMapping public User save(@RequestBody User user){ return user; } // 用户详情 路径参数 @GetMapping("{id}") public User detail(@PathVariable Integer id){ return null; } // 用户更新 @PutMapping public User update(@RequestBody User user){ return user; } // 用户删除 路径参数 @DeleteMapping("{id}") public User delete(@PathVariable Integer id){ return null; } // 多条件模糊查询 param 参数 @GetMapping("search") public List search(String keyword, @RequestParam(required = false, defaultValue = "1") int page, @RequestParam(required = false, defaultValue = "10") int size){ return null; } } ``` 本文由 Alen 创作,采用 知识共享署名4.0 国际许可协议进行许可本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名最后编辑时间为: May 19, 2024 at 10:05 pm