ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Spring Boot图片展示与统一返回格式:从资源映射到泛型封装实战

Spring Boot图片展示与统一返回格式:从资源映射到泛型封装实战 第一部分图片展示问题图片展示前半段请看上一期文章1.1 上传与展示的区别⭐老师强调上传和展示是两个独立步骤——上传只是把文件存进去展示是后续从存储中读取并呈现不能以为传完就自动显示。步骤说明上传把文件存到磁盘如E:/upload/展示从存储中读取并渲染到页面问题现象用户上传图片后前端页面没有变化后端接口仅返回了success状态没有返回图片具体信息前端接收到数据后缺少处理逻辑无法展示图片1.2 图片的特殊性⭐老师强调图片较特殊必须显式引入页面才能展示而word、pdf等一般文件不需要引。!-- 图片必须用img标签引入 -- img srccebbcb019f2f469ca6330d7fb5dbb431.jpg1.3 路径问题⭐老师强调不能直接写文件路径。因为网页默认用http协议加载直接写本地路径对应的是file协议两协议不同浏览器不允许这样加载资源。协议说明http协议网页默认使用file协议本地文件路径使用⭐老师强调传统Tomcat部署目录有文件夹可直接通过路径访问静态资源但Spring Boot内嵌Tomcat无法操作文件在磁盘某处也访问不了。第二部分资源映射配置WebConfig2.1 解决思路⭐老师强调写一个普通Java工具类实现Spring MVC提供的扩展配置接口。该接口能在不修改Spring Boot配置的前提下改变Spring MVC行为。WebMvcConfigurer接口可拦截静态资源可处理跨域接口内含多个方法按需求实现即可2.2 WebConfig代码package com.qcby.util; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; // 资源处理器映射 Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // 访问地址OIP-C.jpg registry.addResourceHandler(/showImg/**) .addResourceLocations(file:E:/upload/); } }2.3 映射规则⭐老师强调访问前缀与本地目录的绑定关系且配置需成对修改保持一致。部分作用示例/showImg/**访问前缀可随意改名xxx.jpgfile:E:/upload/本地磁盘目录E:xxx.jpg映射效果请求 OIP-C.jpg │ ▼ 映射到 file:E:OIP-C.jpg │ ▼ 返回图片给浏览器⭐老师强调这类似给网址起外号指向真实文件夹前缀像门牌后段像房号拼起来才找到文件代码两处要同步改只改一处会导致映射失效第三部分统一返回格式3.1 问题背景⭐老师强调后端接口查单个返回的是对象查所有返回的是数组两者格式不统一。前端拿到对象只能点属性直接用拿到数组却要加循环依次套用得先判断查的是一个还是所有。接口返回类型前端处理查全部List需要循环按id查Student对象直接点属性⭐老师强调这种对象与数组混用的方式不合理应该像之前Servlet那样统一返回格式避免前端额外区分。3.2 统一返回模板⭐老师强调不管查询方式是查全部还是按id查也不管结果有几条返回结构必须统一——业务数据都放在data字段里。返回模板结构{ code: 200, msg: 提示信息, data: 业务数据 }3.3 ResponseResult代码package com.qcby.model;放这 import com.fasterxml.jackson.annotation.JsonInclude; JsonInclude(JsonInclude.Include.NON_NULL) public class ResponseResultT { private Integer code; private String msg; private T data; public ResponseResult(Integer code, String msg, T data) { this.code code; this.msg msg; this.data data; } public ResponseResult(Integer code, T data) { this.code code; this.data data; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg msg; } public T getData() { return data; } public void setData(T data) { this.data data; } }3.4 泛型 vs Object⭐老师强调Object可作为最大父类型来兜底承载数据但更推荐用泛型由调用方传入具体类型灵活且类型安全。对比Object泛型T类型安全需强制转换编译期检查灵活性低高推荐度❌✅3.5 构造方法⭐老师强调至少可定义三个构造方法也可按需简化。// 完整构造含msg public ResponseResult(Integer code, String msg, T data) { ... } // 简化构造不含msg public ResponseResult(Integer code, T data) { ... }⭐老师强调根据传参决定调用哪个构造方法比如传200和list时只返回code和data不带message。3.6 JsonInclude注解⭐老师强调未赋值的引用类型字段如message设为null默认也会输出。若想空值不展示可使用JsonInclude注解。放在ResponseResult上 JsonInclude(JsonInclude.Include.NON_NULL) public class ResponseResultT { // message为空时不输出 }效果对比设置返回结果无注解{code:200,msg:null,data:[...]}有注解{code:200,data:[...]}⭐老师强调区分不赋值和不输出——不赋值是数据状态不输出靠注解控制序列化行为二者不可混淆。第四部分Controller改造4.1 改造前RequestMapping(search) ResponseBody public ListStudent findAll() { ListStudent list studentService.findAll(); return list; // 直接返回List } RequestMapping(searchById) ResponseBody public Student searchById(Integer id) { Student student studentService.findById(id); return student; // 直接返回对象 }4.2 改造后统一格式RequestMapping(search) ResponseBody public ResponseResult findAll() { System.out.println(controller层查找); ListStudent list studentService.findAll(); return new ResponseResult(200, list); // 包进Result } RequestMapping(searchById) ResponseBody public ResponseResult searchById(Integer id) { Student student studentService.findById(id); return new ResponseResult(200, student); // 包进Result }⭐老师强调别直接返裸数据要绕一下包进Result所有数据都放进data字段保持结构统一前端拿到的永远是value.data不用区分对象还是数组附录一完整代码汇总WebConfig.java资源映射package com.qcby.util; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/showImg/**) .addResourceLocations(file:E:/upload/); } }ResponseResult.java统一返回模板package com.qcby.model; import com.fasterxml.jackson.annotation.JsonInclude; JsonInclude(JsonInclude.Include.NON_NULL) public class ResponseResultT { private Integer code; private String msg; private T data; public ResponseResult(Integer code, String msg, T data) { this.code code; this.msg msg; this.data data; } public ResponseResult(Integer code, T data) { this.code code; this.data data; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg msg; } public T getData() { return data; } public void setData(T data) { this.data data; } }StudentController.javapackage com.qcby.controller; import com.qcby.entity.Student; import com.qcby.model.ResponseResult; import com.qcby.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.List; Controller public class StudentController { Autowired StudentService studentService; RequestMapping(search) ResponseBody public ResponseResult findAll() { System.out.println(controller层查找); ListStudent list studentService.findAll(); return new ResponseResult(200, list); } RequestMapping(searchById) ResponseBody public ResponseResult searchById(Integer id) { Student student studentService.findById(id); return new ResponseResult(200, student); } RequestMapping(delete) ResponseBody public int delete(Integer id) { int code studentService.delete(id); return code; } }index.html图片展示!-- 上传表单 -- form classfilebox 选择文件:input typefile classfile namefile input typebutton classbtn value上传 /form !-- 图片展示路径指向映射前缀 -- img srccebbcb019f2f469ca6330d7fb5dbb431.jpg !-- 文件下载 -- h3文件下载/h3 div classblock div服务器保存文件名(saveFileName)/div input typetext classdownFileName placeholder上传成功后复制saveFileName填入 button class内部工具Btn下载文件/button /div
返回列表