04 SpringMVC响应数据之两种方式实现页面跳转控制+返回JSON数据+返回静态资源+数据格式化

本文详细介绍了SpringMVC中的handler方法分析,包括参数接收、业务调用和响应数据处理。此外,还涵盖了页面跳转控制(视图解析器、视图控制器、跳转与重定向)、返回JSON数据、配置静态资源处理和自定义Formatter的使用方法。
摘要由CSDN通过智能技术生成

1. handler方法分析

/**
 * TODO: 一个controller的方法是控制层的一个处理器,我们称为handler
 * TODO: handler需要使用@RequestMapping/@GetMapping系列,声明路径,在HandlerMapping中注册,供DS查找!
 * TODO: handler作用总结:
 *       1.接收请求参数(param,json,pathVariable,共享域等) 
 *       2.调用业务逻辑 
 *       3.响应前端数据(页面(不讲解模版页面跳转),json,转发和重定向等)
 * TODO: handler如何处理呢
 *       1.接收参数: handler(形参列表: 主要的作用就是用来接收参数)
 *       2.调用业务: { 方法体  可以向后调用业务方法 service.xx() }
 *       3.响应数据: return 返回结果,可以快速响应前端数据
 */
@GetMapping
public Object handler(简化请求参数接收){
    调用业务方法
    返回的结果 (页面跳转,返回数据(json))
    return 简化响应前端数据;
}

总结:

通过handler的形参列表接收请求数据

通过handler的return关键字响应前端数据(视图或JSON)


2. 页面跳转控制

https://blog.csdn.net/m0_59735420/article/details/128126514

configureViewResolvers 则是用于配置更复杂的视图解析器,例如定义不同后缀的视图,或者添加自定义的视图解析器。

addViewControllers 主要用于简单的视图跳转,对于简单的页面导航,不需要业务逻辑的情况,可以直接使用这个方法进行配置。因为该方法不需要配置Controller.

2.1 configureViewResolvers视图解析器返回模板视图页面

什么是返回模板视图页面?

采用轻度的前后端分离项目时, 前端代码未完成与后端解耦合, 前端的代码(如视图)仍存在于整体项目中

目标 : 用户访问localhost:8080/jsp/index时,返回给用户本地webapp-WEB-INF-view下的home.jsp页面.

  1. pom文件添加jsp依赖
<!-- jsp需要依赖! jstl-->
<dependency>
    <groupId>jakarta.servlet.jsp.jstl</groupId>
    <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
    <version>3.0.0</version>
</dependency>
  1. 创建等会要返回的home.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Title</title>
  </head>
  <body>
        <!-- 可以获取共享域的数据,动态展示! jsp== 后台vue -->
        ${msg}
  </body>
</html>

  1. 新建一个MvcConfig类
//本类中要重写handlerMapping,handlerAdapter两个方法,配置一个json转化器, 通过一个注解@EnableWebMvc实现

@EnableWebMvc  //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.sunsplanter.controller") // 进行controller扫描

public class SpringMvcConfig implements WebMvcConfigurer {

   //配置一个jsp对应的视图解析器
    public void configureViewResolvers(ViewResolverRegistry registry) {
        //稍后的handler中如果想给前端返回 /WEB-INF/views/index .jsp
        //Resigter可以帮忙添加前后缀
        registry.jsp("/WEB-INF/views/",".jsp");
    }
}
  1. 编写jspController类
/**
 *  跳转到提交文件页面  
 *  
 *  如果要返回jsp页面!
 *     1.方法返回值改成字符串类型
 *     2.返回逻辑视图名即可    
 *         <property name="prefix" value="/WEB-INF/views/"/>
 *            + 逻辑视图名 +
 *         <property name="suffix" value=".jsp"/>
 */
 //访问localhost:8080/jsp/index时,返回给用户本地webapp-WEB-INF-view下的home.jsp页面.
@GetMapping("index")
public String jumpJsp(Model model){
    System.out.println("FileController.jumpJsp");
    return "home";
}

2.2 addViewControllers视图控制器返回模板视图页面

对于上例, HTML代码不变, Controller方法删除, 仅将MvcConfig中的方法更换为:

// 跳转视图页面控制器
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index").setViewName("home");
}

同样可以实现进入index页面则自动返回一个视图.

2.3 跳转和重定向

重定向与跳转的区别:
s
1.请求的次数的不同 : 重定向总共请求了两次服务器;转发则是用户请求一次可能经过N个JSP页面由返回到用户浏览器中,是一次请求多次处理的过程;

2.跳转过程中链接的变化不同 : ,重定向在跳转中请求了两次服务器并且是两次不同的链接地址,在浏览器的地址栏可以看到两次是有变化的;转发在跳转过程中浏览器请求了一次服务器,服务器经过了n个JSP页面并没有改变请求的链接地址,因为用户只请求了一次,所以在整个跳转过程中链接地址是没有改变的,在浏览器的地址栏就可以看到

3.目的不同 : 重定向只是简单的让用户访问一个新的链接,而转发是服务器要得到用户的请求内容并需要进行一部分处理的,所以两者目的之不同的

  • 不管是重定向(redirect)还是转发(forward),其handler都要设置String类型
  • 语法为 return 关键字: /路径,不需要额外注解
  • @ResponseBody注解和转发/重定向是互斥的。@ResponseBody注解的类会快速返回,不走视图解析器,也不会再转发/重定向。
  • 注意:如果是项目下的资源,转发和重定向都一样都是项目下路径!都不需要添加项目根路径!
@RequestMapping("/redirect-demo")
public String redirectDemo() {
    // 重定向到 /demo 路径 
    return "redirect:/demo";
}

@RequestMapping("/forward-demo")
public String forwardDemo() {
    // 转发到 /demo 路径
    return "forward:/demo";
}

3.返回JSON数据

  1. 如上章接收JSON数据一样,涉及JSON必须要添加依赖以及在config类中配置JSON转换器(@EnableWebMvc)。
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.0</version>
</dependency>
  1. 如上章接收JSON数据一样(@RequestBody),使用@ResponseBody注解返回JSON数据,该注解的作用在于将返回的对象序列化为 JSON 或 XML 格式的数据,并发送给客户端。
  2. 需注意的是ResponseBody不经过视图解析器,且与转发/重定向互斥。
@GetMapping("/accounts/{id}")
@ResponseBody
public Object handle() {
  // ...
  return obj;
}

测试方法:

@Controller
@RequestMapping(value = "/user/detail", method = RequestMethod.POST)
@ResponseBody
public User getUser(@RequestBody User userParam) {
    System.out.println("userParam = " + userParam);
    User user = new User();
    user.setAge(18);
    user.setName("John");
    //返回的对象,会使用jackson的序列化工具,转成json返回给前端!
    return user;
}

合并两条注解:
@Controller+@ResponseBody = @RestController

3.configureDefaultServletHandling返回静态资源

什么是静态资源?
资源本身已经是可以直接拿到浏览器上使用的程度了,不需要在服务器端做任何运算、处理。典型的静态资源包括:
- 纯HTML文件/图片
- CSS文件
- JavaScript文件

如何让外部能够访问静态资源?

  • DispatcherServlet 的 url-pattern 配置的是“/”,表示整个 Web 应用范围内所有请求都由 SpringMVC 来处理
  • 而对 SpringMVC 来说,若想某个url被后台处理,必须将这个urll用 @RequestMapping 绑定到某个handler上,才能找到处理请求的方法,否则handlermapping(秘书)无法知道找哪个handler(打工人)处理这个链接。
  • 因此,思路是显然的,那就是想办法让系统知道,如果请求的是url是xxx/xxx/car.jpg , 那就从静态资源中直接提取而不是找handler(静态资源不可能存进handler里)。
  1. 准备好静态资源并编译:
    在这里插入图片描述
    在这里插入图片描述2. 在config类中开启静态资源处理:
@EnableWebMvc  //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.sunsplanter.controller") //
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 
public class SpringMvcConfig implements WebMvcConfigurer {
    //开启静态资源处理
    //处理的顺序是DispatcherServlet --> handlerMapping -->没找到就去找静态资源
    //平时第二步走完就结束,该方法多走一步为了找到静态资源
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

访问localhost:8080/images/car.jpg , 可以正常显示.

addFormatters 数据格式化

  • Formatter 和 Converter<S,T> 都是数据转换接口,将一种数据类型转换为另一种数据类型。
  • Formatter只能将 String 类型转为其他数据数据类型。
    这点在Web 应用适用更广。因为 Web 请求的所有参数都是 String,我们需要把 String 转为 Integer ,Long,Date 等

.1 接口原型

public interface Formatter<T> extends Printer<T>, Parser<T> {
}

Formatter是一个组合接口,没有自己的方法。内容来自 Printer和 Parser

Printer:将 T 类型转为 String,格式化输出
Parser:将 String 类型转为期望的 T 对象。

.2 Spring已经实现的Formatter

前述已经提到, Formatter是一个接口, 而Spring已经帮我们实现了常用的几个类

  • DateFormatter : String 和 Date 之间的解析与格式化

  • NumberFormat :String 和 Number 之间的解析与格式化

  • InetAddressFormatter :String 和 InetAddress 之间的解析与格式化

  • PercentStyleFormatter :String 和 Number 之间的解析与格式化,带货币符号

    • Formatter也是 Spring 的扩展点,我们处理特殊格式的请求数据时,如果以上四种对象不能满足, 我们可以自己实现合适的 Formatter,重写 Print 和 Parse 方法, 将请求的 String 数据转为我们的某个对象,使用这个对象更方便我们的后续编码。

.3 Formatter生效的时间节点

当Controller接收到前端的参数时, 会先寻找已注册的 XXXFormatter 进行类型转换。

具体到接下来的例子,

  1. Controller层指定接收的参数为DeviceInfo类型
  2. Spring寻找所有已经注册的XXXFormatter,发现 "public class DeviceFormatter implements Formatter " ,即DeviceFormatter是为DeviceInfo类型进行类型转换的,
  3. 就调用该类中的parse方法 , 将传入的东西(String字符串)转换成DeviceInfo对象并赋值进去,今后可以直接使用deviceInfo,里面的属性已被正确赋值
  4. 等到Controller层的return语句时, 会再次调用该类的Print方法转化为字符串.

.4 自定义Formatter尝试

需求: 接收前端传来的字符串 “1111;2222;333,NF;4;561”,并在代码中用 DeviceInfo 存储参数值
在这里插入图片描述

.4.1 实体类

import lombok.Data;

@Data
public class DeviceInfo {
    private String item1;
    private String item2;
    private String item3;
    private String item4;
    private String item5;
}

.4.2 自定义Formatter

import com.sunsplanter.sf2.pojo.DeviceInfo;
import org.springframework.format.Formatter;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.util.Locale;
import java.util.StringJoiner;

public class DeviceFormatter implements Formatter<DeviceInfo> {

    //重写parse方法将 String 数据转为 DeviceInfo
    //Locale对象可以限定日期, 语言, 数字等格式, 为了重写parse方法必须要带上这个参数, 但本次不需要使用
    @Override
    public DeviceInfo parse(String text, Locale locale) throws ParseException {
        DeviceInfo deviceInfo = null;

        //如果传入字符串即不为NULL也不未空("")
        if (StringUtils.hasLength(text)) {

            //每次遇到";"就分割字符串并存入数组
            String[] items = text.split(";");

            deviceInfo = new DeviceInfo();
            deviceInfo.setItem1(items[0]);
            deviceInfo.setItem2(items[1]);
            deviceInfo.setItem3(items[2]);
            deviceInfo.setItem4(items[3]);
            deviceInfo.setItem5(items[4]);
        }
        return deviceInfo;
    }

    //将 DeviceInfo 转为 String
    //将 DeviceInfo 对象的属性 item1 和 item2 以 # 为分隔符拼接成一个字符串
    @Override
    public String print(DeviceInfo object, Locale locale) {
        StringJoiner joiner = new StringJoiner("#");
        joiner.add(object.getItem1()).add(object.getItem2());

        return joiner.toString();
    }
}

.4.3 在MVCConfig类中注册该Formatter

import com.sunsplanter.sf2.formatter.DeviceFormatter;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MVCConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/welcome").setViewName("index");
    }
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new DeviceFormatter());
    }
}
  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值