Spring Web MVC从入门到实战

Spring Web MVC从入门到实战
—JavaEE专栏—


1. Spring Web MVC核心概念

在这里插入图片描述

1.1 什么是Spring Web MVC

Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就包含在Spring框架中,其正式名称来源于源模块名称(spring-webmvc),通常简称为Spring MVC。

官方定义:Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning.

Servlet是Java Web开发的规范,定义了动态页面开发的技术标准,而Tomcat、Weblogic等Servlet容器则是该规范的具体实现,负责管理开发者编写的Servlet类。Spring MVC基于Servlet规范实现,为Web应用开发提供了完整的解决方案。

1.2 MVC设计模式深度解析

MVC是Model View Controller的缩写,是软件工程中的一种软件架构设计模式,将软件系统分为模型、视图和控制器三个基本部分,实现业务逻辑与界面展示的解耦。

1.2.1 MVC三大组件职责
  • Model(模型):应用程序的主体部分,负责处理数据逻辑和业务逻辑,包含数据的存储、处理和运算。
  • View(视图):专门用于与用户交互的界面,负责数据展示和接收用户操作,如HTML页面、移动端界面等。
  • Controller(控制器):作为视图与模型之间的桥梁,接收用户请求,选择对应的模型进行处理,并将处理结果通过视图返回给用户。
1.2.2 定义图与类比理解
MVC定义图

Spring MVC定义图

以饭店就餐场景为例,直观理解MVC组件的分工:

  • 服务员(View):接待顾客、记录点餐信息、上菜,负责与用户直接交互。
  • 前厅(Controller):接收服务员传递的订单,分配给对应的后厨处理,协调前后端流程。
  • 后厨(Model):根据订单需求制作菜品,处理核心业务逻辑。

1.3 Spring MVC与Spring Boot的关系

Spring Boot并非替代Spring MVC的框架,而是实现Spring MVC的一种便捷方式。两者的关系可通过下表清晰区分:

特性Spring MVCSpring Boot
本质Web框架,实现MVC模式快速开发脚手架
核心作用处理Web请求与响应简化Spring应用配置与部署
依赖关系可独立使用可集成Spring MVC实现Web功能
发布时间2004年2014年

类比理解:Spring Boot如同一个功能完备的厨房,而Spring MVC则是厨房中实现烹饪功能的燃气灶和厨具。厨房(Spring Boot)可通过配置不同工具实现多种功能,而烹饪(Web开发)功能的核心实现依赖于燃气灶(Spring MVC)。

2. Spring MVC项目搭建与环境配置

2.1 项目创建步骤

Spring MVC项目通过Spring Boot方式创建,步骤如下:

  1. 新建Spring Boot项目,选择Spring Boot版本(推荐3.2.0及以上)。
  2. 在依赖选择界面勾选Spring Web模块(即Spring MVC核心依赖)。
  3. 配置项目基本信息(Group、Artifact、Package等),完成项目创建。

2.2 核心依赖说明

创建后的项目pom.xml文件中,Spring Web依赖自动引入,核心依赖代码如下:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

该依赖包含Spring MVC核心组件、Servlet API、Tomcat嵌入式容器等关键资源,无需额外配置即可实现Web功能开发。

3. Spring MVC核心注解与应用

3.1 路由映射注解@RequestMapping

@RequestMapping是Spring MVC中最基础的路由映射注解,用于将URL请求与Java方法关联,支持修饰类和方法。

基础使用示例:

@RestController@RequestMapping("/user")// 类级路由前缀publicclassUserController{// 方法级路由,完整访问路径:/user/sayHi@RequestMapping("/sayHi")publicStringsayHi(){return"hello, Spring MVC";}}
  • 类级注解:设置请求路径的初始前缀,所有方法路由需拼接该前缀。
  • 方法级注解:设置具体的请求路径,可支持多层路径(如/say/hi)。
  • 路径规则:URL路径最前是否加/不影响访问,Spring会自动补全(路径+请求方式是唯一的,可以相同的路径名字但是不同类型的请求)。

3.2 请求参数接收注解

3.2.1 @RequestParam参数重命名

用于解决前后端参数名称不一致问题,同时可设置参数是否必传:

@RequestMapping("/r6")// 此处@RequestParam("sa")注解的作用是参数重命名,publicStringr6(@RequestParam(value ="sa", required =false)String resouce){return"接收到 resouce = "+ resouce;}
  • value属性:指定前端传递的参数名称。
  • required属性:默认值为true,设置为false时参数非必传。
3.2.2 @PathVariable获取路径参数

用于从URL路径中直接提取参数,适用于RESTful风格接口:

@RequestMapping("/r11/{articleId}/{type}")publicStringr11(@PathVariable("articleId")Integer id,@PathVariableString type){return"接收到的参数 articleId = "+ id +", type = "+ type;}

访问路径示例:http://127.0.0.1:8080/param/m8/5/zhangsan,其中5和zhangsan分别映射到id和userName参数。

3.3 响应处理注解

  • @ResponseBody:标识方法返回数据而非视图,可修饰类或方法。
  • @RestController:组合注解,等价于@Controller + @ResponseBody,类中所有方法默认返回数据。

两者区别示例:

// 返回视图(需配合模板引擎)@ControllerpublicclassIndexController{@RequestMapping("/index")publicStringindex(){return"/index.html";}}// 返回数据@RestControllerpublicclassDataController{@RequestMapping("/data")publicStringgetData(){return"这是返回的数据内容";}}

4. 请求处理全场景实战

4.1 基础参数传递

4.1.1 单个参数接收

直接通过方法参数接收前端传递的参数,参数名称需与请求参数一致:

@RequestMapping("/r1")publicStringr1(String name){return"接收到参数 name = "+ name;}

通过postman创建一个带有name参数请求访问示例:
http://127.0.0.1:8080/request/r1?name=zhangsan

在这里插入图片描述
4.1.2 多个参数接收

支持多个参数同时接收参数顺序不影响绑定结果(请求的参数名称保持一致即可)

@RequestMapping("/r4")publicStringr4(String name,String password,Integer age){// 此处字符串拼接不考虑性能return"接收到参数 name = "+ name +", password = "+ password +", age = "+ age;}

通过postman创建一个带有age,password,name参数请求访问示例:
http://127.0.0.1:8080/request/r4?age=20&name=zhangsan&password=123456

在这里插入图片描述

4.2 复杂参数处理

4.2.1 对象参数接收

当参数较多时,可封装为实体类接收,Spring会自动按属性名绑定

// 实体类publicclassPerson{privateString name;privateString password;privateint age;publicStringgetName(){return name;}publicStringgetPassword(){return password;}publicintgetAge(){return age;}publicvoidsetName(String name){this.name = name;}publicvoidsetPassword(String password){this.password = password;}publicvoidsetAge(int age){this.age = age;}@OverridepublicStringtoString(){return"Person{"+"name='"+ name +'\''+",+ password +'\''+", age="+ age +'}';}}// 接口方法@RequestMapping("/r5")publicStringr4(Person person){return"接收到参数 person = "+ person;}

创建post请求访问示例:http://127.0.0.1:8080/request/r5

在这里插入图片描述
4.2.2 参数重命名

通过@RequestParam()注解使得参数进行重命名与前端发的请求保持一致
且加了这个注解,此参数就为必传参数,如果不传则会报出400状态,除非将@RequestParam("sa")修改为@RequestParam(value = "sa", required = false)

@RequestMapping("/r6")// 此处@RequestParam()注解的作用是参数重命名publicStringr6(@RequestParam("sa")String resouce){return"接收到 resouce = "+ resouce;}

访问示例:http://127.0.0.1:8080/request/r6?sa=fyb_n_homepage

在这里插入图片描述
4.2.3 数组与集合参数

数组参数接收:

@RequestMapping("/r7")publicStringr7(String[] names){return"接收到参数 names = "+Arrays.toString(names);}

访问示例:
http://127.0.0.1:8080/request/r7?names=zhangsan&names=lisi&names=wangwu

在这里插入图片描述

也可以使用
http://127.0.0.1:8080/request/r7?names=zhangsan,lisi,wangwu

在这里插入图片描述

集合参数接收(需配合@RequestParam):

@RequestMapping("/r8")// @RequestParam 在这里的作用是将请求中的参数绑定到方法的 List<String> names 参数上publicStringr8(@RequestParamList<String> names){return"接收到的参数 names = "+ names;}

未使用@RequestPram绑定如图会报出500错误

在这里插入图片描述


绑定@RequestPram则正常状态

在这里插入图片描述

4.3 传递JSON数据

4.3.1 JSON 概念与优势

JSON(JavaScript Object Notation,JavaScript 对象表示法)是一种轻量级的文本数据交互格式 ,基于 ECMAScript 规范的子集,采用独立于编程语言的语法存储和描述数据,核心作用是实现不同语言、不同系统间的数据传递与交换。
其核心优势如下:

  • 简单易用:语法贴近日常认知,仅需通过键值对、对象、数组三种结构即可描述数据,学习成本低,上手快; 跨平台兼容:支持 Java、Python、JavaScript、Go 等几乎所有主流编程语言,可在前后端、不同服务间无缝传输;
  • 轻量高效:相比 XML格式,JSON 数据无冗余标签,体积更小,传输时占用带宽少,能显著提升数据传输速度;
  • 结构灵活:支持对象嵌套数组、数组嵌套对象等复杂结构,可满足用户信息、订单详情等多维度数据描述需求;
  • 安全性高:本质是纯文本格式,不包含任何可执行代码,避免恶意脚本注入风险,常用于 Web 应用前后端交互、API 接口数据传输场景。
4.3.2 JSON 语法与核心结构

JSON 语法遵循严格规则,错误语法会导致解析失败,需重点关注以下要点:

1. 基础语法规则:

  • 数据以键值对(Key/Value)形式存储,Key 必须用双引号包裹(不可用单引号)
  • 不同数据之间用逗号分隔,末尾不可加多余逗号
  • 字符串类型值需用双引号包裹,数字、布尔值无需包裹
  • 注释:标准 JSON 不支持注释(部分解析工具如 JSON5
    支持,但不推荐跨系统使用)。

2. 两种核心结构:

  • 对象结构:用大括号{}包裹,存储无序键值对集合,适用于描述单个实体(如用户、商品),示例:
{ "userId": 1001, "userName": "zhangsan", "age": 25, "isStudent": false, "hobbies": ["reading", "coding"] } 

数组结构:用中括号[]包裹,存储有序值列表,值类型可混合(如字符串、数字、对象),适用于描述多个同类实体(如用户列表、商品列表),示例:

[ {"bookId": 1, "bookName": "Spring MVC实战"}, {"bookId": 2, "bookName": "Java核心技术"}, 3.14, "JSON教程" ] 

3. 合法 JSON 示例:
单个对象:{"name":"admin","age":18}
纯数组:["hello", 3.14, true]
对象数组:[{"name":"admin","age":18},{"name":"root","age":20}]

可通过在线 JSON 校验工具(如Be JSON)验证语法正确性,避免因格式错误导致接口解析失败。
4.3.3 JSON 与 Java 对象互转(核心工具)

Spring MVC 框架默认集成jackson-databind工具包(Spring Web 依赖已包含),无需额外引入,可直接实现 JSON 字符串与 Java 对象的 “序列化”(对象转 JSON)和 “反序列化”(JSON 转对象)。

转换工具类实现
通过ObjectMapper类(jackson-databind 核心类)提供的方法完成转换,示例代码如下:

packagecn.overthinker.springboot;importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.junit.jupiter.api.Test;publicclassJSONTests{privatestaticObjectMapper objectMapper =newObjectMapper();publicstaticvoidmain(String[] args)throwsJsonProcessingException{Person person =newPerson(); person.setName("zhangsan"); person.setAge(18); person.setPassword("123456");// 对象转json字符串String s = objectMapper.writeValueAsString(person);System.out.println(s);//json字符串转对象String json ="{\"name\":\"zhangsan\",\"age\":18,\"password\":\"123456\"}";Person person1 = objectMapper.readValue(json,Person.class);System.out.println(person1);}}

关键方法说明

  • writeValueAsString(Object obj):将 Java 对象转为 JSON 字符串,支持实体类、集合、Map等类型;
  • readValue(String jsonStr, Class valueType):将 JSON 字符串转为指定类型的Java 对象,需传入目标类的 Class对象;
  • 若转换集合(如List),需用TypeReference指定泛型类型,示例:
List<Person> personList = objectMapper.readValue("[{\"id\":1,\"name\":\"zhangsan\"},{\"id\":2,\"name\":\"lisi\"}]",newTypeReference<List<Person>>(){});
4.3.4 Spring MVC 接收 JSON 请求

1. 前端请求方式(以 Postman 为例)

Postman 是后端开发常用的接口测试工具,传递 JSON 参数步骤如下:

  • 选择请求方式:推荐用 POST(GET 请求也支持,但JSON 数据需拼在 URL 中,不适用于复杂数据);
  • 设置请求URL:如http://127.0.0.1:8080/request/r9

配置请求头:在Headers标签中添加Content-Type:application/json(必须设置,告知后端请求数据格式为 JSON,否则解析失败);

在这里插入图片描述

2. 后端接口实现
后端需通过@RequestBody注解绑定请求正文,触发 Spring 的 JSON 解析逻辑,实现参数自动封装。

@RequestMapping("/r9")publicStringr9(@RequestBodyPerson person){return"接收到的参数 person = "+ person;}

3. Fiddler抓包结果

在这里插入图片描述

4.4文件上传功能实现

使用@RequestPart注解实现文件上传功能:

@RequestMapping("/r12")// 处理文件上传的请求方法,MultipartFile是Spring提供的文件上传封装类// throws IOException:声明可能抛出的IO异常(文件读写时可能发生)publicStringr12(MultipartFile file)throwsIOException{// 1. 获取表单中文件参数的名称(即前端<input type="file" name="file">中的name值)// 注意:此名称是前端表单控件的name属性值,而非实际文件名System.out.println("表单文件参数名:"+ file.getName());// 2. 获取上传文件的原始名称(包含文件名和扩展名,如"test.jpg")// 该名称来自客户端本地文件的名称,可能包含路径(不同浏览器处理不同,需注意)System.out.println("文件原始名称:"+ file.getOriginalFilename());// 3. 获取文件的MIME类型(如图片为"image/jpeg",文本为"text/plain")// 用于判断文件类型,可用于限制上传文件格式(如只允许图片上传)System.out.println("文件MIME类型:"+ file.getContentType());// 4. 定义文件保存路径和文件名// 这里将文件保存到本地"D:/temp/"目录,文件名使用原始文件名// 注意:需确保"D:/temp/"目录已存在,否则会抛出文件找不到异常File destFile =newFile("D:/temp/"+ file.getOriginalFilename());// 5. 将上传的文件内容转移到目标文件中// transferTo()是Spring提供的便捷方法,内部处理了文件流的读写和关闭// 替代了传统的InputStream/OutputStream手动读写逻辑,更安全高效 file.transferTo(destFile);// 6. 返回上传成功的提示信息return"接受到文件,已保存至D:/temp目录";}
在这里插入图片描述

4.5 Cookie与Session会话管理

下述图中的"令牌"通常就存储在 Cookie 字段中,

在这里插入图片描述
4.5.1 Cookie操作

方式一:
通过HttpServletRequest 和HttpServletResponse 获取Cookie:

importjakarta.servlet.http.Cookie;importjakarta.servlet.http.HttpServletRequest;importjakarta.servlet.http.HttpServletResponse;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/request2")publicclassRequestController2{/*** * 读取cookie */@RequestMapping("/getCookie")publicStringgetCookie(HttpServletRequest request,HttpServletResponse response){Cookie[] cookies = request.getCookies();if(cookies !=null){for(Cookie cookie : cookies){System.out.println(cookie.getName()+":"+ cookie.getValue());}}return"获取Cookie成功";}}

方式二:
注解的方式

@RequestMapping("/getCookie2")// 要求客户端必须返回含class名称的cookiepublicStringgetCookie2(@CookieValue("class")String className){return"获取Cookie成功 className:"+ className;}

演示步骤

在idea启动服务器,打开浏览器新标签页,输入http://127.0.0.1:8080/request2/getCookie,显示获取Cookie成功

在这里插入图片描述

F12打开控制面板,选择Application,在左侧栏有个Cookies选项,点击找到http://127.0.0.1:8080,可以通过手动添加或者修改Cookie的值

在这里插入图片描述

修改完后通过,进行页面刷新,回到idea观察日志,或者通过Fiddler抓包观察

在这里插入图片描述


在这里插入图片描述
4.5.2 Session操作

Session存储与读取:

方案一
@RequestMapping("/setSession")publicStringsetSession(HttpServletRequest request){HttpSession session = request.getSession(); session.setAttribute("name","zhangsan"); session.setAttribute("age",20);return"设置Session成功";}@RequestMapping("/getSession")publicStringgetSession(HttpServletRequest request){HttpSession session = request.getSession();String name =(String) session.getAttribute("name");Integer age =(Integer) session.getAttribute("age");return"从session中获取数据, name:"+ name +", age:"+ age;}

因为Session 是存储在服务器端的会话数据, 客户端(浏览器)无法直接访问服务器内存里的 Session 内容,只能通过后端接口 “间接读取”——getSession接口的作用就是把服务器内存里的 Session 数据返回给客户端,让前端能拿到这些信息(比如展示用户名称)。

在浏览器输入http://127.0.0.1:8080/request2/setSession刷新页面观察到session已经设置成功,同时打开f12,发现有一行数据就是sessionID

在这里插入图片描述


打开另一标签页输入http://127.0.0.1:8080/request2/getSession,可以观察到保存在session里面的信息

在这里插入图片描述
方案二:使用HttpSession
// 通过HttpSession直接获取session@RequestMapping("/getSession")publicStringgetSession(HttpSession session){// 获取用户信息String name =(String) session.getAttribute("name");Integer age =(Integer) session.getAttribute("age");return"从session中获取数据, name:"+ name +", age:"+ age;}
方案三:通过@SessionAttribute注解
@RequestMapping("/getSession3")publicStringgetSession3(@SessionAttribute("name")String name){// 获取用户信息return"从session中获取数据, name:"+ name;}
在这里插入图片描述


在这里插入图片描述
提问与思考
当我们将name改为可自己输入的参数时,然后用设置不同的cookie的name参数值,那么它们如果交换sessionid,保存的信息也会交换吗?🤔

使用代码

/*** * 读取session * @param request * @return */@RequestMapping("/setSession")publicStringsetSession(HttpServletRequest request,String name){HttpSession session = request.getSession(); session.setAttribute("name", name); session.setAttribute("age",20);return"设置Session成功";}// 通过HttpSession直接获取session@RequestMapping("/getSession2")publicStringgetSession(HttpSession session){// 获取用户信息String name =(String) session.getAttribute("name");Integer age =(Integer) session.getAttribute("age");return"从session中获取数据, name:"+ name +", age:"+ age;}

创建第二个Session(EDGE)

在这里插入图片描述


创建第一个Session(Chrome)
http://127.0.0.1:8080/request2/setSession?name=wangwu

在这里插入图片描述


在这里插入图片描述


得到的第一个SessionID为B76C84D38B4C522CAD16AE849F23414F

得到的第一个SessionID为FFC3B941551E94012D87BBBF3C95BC8A

将edge的sessionid替换为chrome的sessionid,观察现象

在这里插入图片描述


很明显的看到name值已经发生了改变,说明了Session 是基于服务器端的会话标识(SessionID)来区分用户的,不同客户端(浏览器)通过 SessionID 关联到对应的 Session 数据,同时服务器完全依赖 SessionID 来定位对应的 Session 数据

4.6获取Header

方案一

@RequestMapping("/getHeader")publicStringgetHeader(HttpServletRequest request){String userAgent = request.getHeader("User-Agent");return"从Header获取数据, userAgent"+ userAgent;}

方案二
使用@RequestHeader注解

//使用注解@RequestMapping("/getHeader2")publicStringgetHeader(@RequestHeader("User-Agent")String userAgent){return"从Header获取数据, userAgent"+ userAgent;}

运行结果(方案一)

在这里插入图片描述

5. 响应处理高级应用

5.1 静态页面返回

返回静态页面需使用@Controller注解(而非@RestController):

在这里插入图片描述
@ControllerpublicclassIndexController{@RequestMapping("/index")publicObjectindex(){return"/index.html";}}

静态页面需放置在resources/static目录下,访问路径为:http://127.0.0.1:8080/index

5.2 JSON数据响应

Spring MVC可自动将对象转换为JSON格式响应:
示例一

@RequestMapping("/returnJson")@ResponseBodypublicHashMap<String,String>returnJson(){HashMap<String,String> map =newHashMap<>(); map.put("Java","Java Value"); map.put("MySQL","MySQL Value"); map.put("Redis","Redis Value");return map;}

响应结果:

{"Java":"Java Value","MySQL":"MySQL Value","Redis":"Redis Value"}

示例二

@ResponseBody@RequestMapping("/returnJSON")publicPersonreturnJSON(){// 实例化数据模型对象Person person =newPerson();// 设置对象属性 person.setName("zhangsan"); person.setAge(18); person.setPassword("123456");// 返回对象,由 @ResponseBody 自动转换为 JSONreturn person;}

响应结果:

{"name":"zhangsan","password":"123456","age":18}

5.3 响应状态码与Header设置

设置响应状态码:

@RequestMapping("/setStatus")@ResponseBodypublicStringsetStatus(HttpServletResponse response){ response.setStatus(401);// 未授权状态码return"设置状态码成功";}

设置自定义Header:

@RequestMapping("/setHeader")@ResponseBodypublicStringsetHeader(HttpServletResponse response){ response.setHeader("MyHeader","MyHeaderValue");return"设置Header成功";}

6. 综合项目实战

6.1 加法计算器

6.1.1 接口设计
  • 请求路径:/calc/sum
  • 请求方式:GET/POST
  • 参数:num1(Integer,必填)、num2(Integer,必填)
  • 响应:计算结果HTML页面
6.1.2 后端代码
@RestController@RequestMapping("/calc")publicclassCalcController{@RequestMapping("/sum")publicStringsum(Integer num1,Integer num2){Integer sum = num1 + num2;return"<h1>计算机计算结果: "+ sum +"</h1>";}}
6.1.3 前端页面
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>加法计算器</title></head><body><formaction="calc/sum"method="post"><h1>计算器</h1> 数字1:<inputname="num1"type="text"><br> 数字2:<inputname="num2"type="text"><br><inputtype="submit"value="点击相加"></form></body></html>
效果演示
在这里插入图片描述


在这里插入图片描述

6.2 用户登录系统

6.2.1 核心功能
  1. 账号密码校验
  2. 登录状态保持(Session)
  3. 首页显示当前登录用户
6.2.2 后端代码
@RestController@RequestMapping("/user")publicclassLoginController{// 登录校验@RequestMapping("/login")publicbooleanlogin(String userName,String password,HttpSession session){if(!StringUtils.hasLength(userName)||!StringUtils.hasLength(password)){returnfalse;}// 模拟数据库校验if("zhangsan".equals(userName)&&"123456".equals(password)){ session.setAttribute("userName", userName);returntrue;}returnfalse;}// 获取当前登录用户@RequestMapping("/getLoginUser")publicStringgetLoginUser(HttpSession session){String userName =(String) session.getAttribute("userName");if(StringUtils.hasLength(userName)){return userName;}return"";}}

6.3 图书管理系统

6.3.1 系统功能
  1. 用户登录验证
  2. 图书列表展示
  3. 图书状态处理
6.3.2 核心代码

图书列表接口:

@RestController@RequestMapping("/book")publicclassBookController{@RequestMapping("/getList")publicList<BookInfo>getList(){BookService bookService =newBookService();return bookService.getBookList();}}

前端页面渲染:

functiongetBookList(){ $.ajax({ type:"get", url:"/book/getList",success:function(result){if(result !=null){var finalHtml ="";for(var book of result){ finalHtml +='<tr>'; finalHtml +='<td><input type="checkbox" name="selectBook"+ book.id +'"></td>'; finalHtml +='<td>'+ book.id +'</td>'; finalHtml +='<td>'+ book.bookName +'</td>'; finalHtml +='<td>'+ book.author +'</td>'; finalHtml +='<td>'+ book.count +'</td>'; finalHtml +='<td>'+ book.price +'</td>'; finalHtml +='<td>'+ book.publish +'</td>'; finalHtml +='<td>'+ book.statusCN +'</td>'; finalHtml +='<td><a href="book_update.html?bookId='+ book.id +'">修改</a> | <a href="javascript:deleteBook('+ book.id +')">删除</a></td>'; finalHtml +="</tr>";}$("tbody").html(finalHtml);}}});}

7. 开发工具与效率提升

7.1 Postman接口测试

Postman是后端开发常用的接口测试工具,支持多种请求方式、参数类型,无需编写前端代码即可完成接口测试。

核心使用步骤:

  1. 下载安装:Postman官方下载
  2. 创建请求:选择请求方式(GET/POST)、输入URL
  3. 配置参数:根据接口类型选择参数格式(Query Params、form-data、JSON等)
  4. 发送请求:点击Send按钮,查看响应结果

工作界面展示

在这里插入图片描述

7.2 Lombok简化开发

Lombok是Java开发工具库,通过注解自动生成getter/setter、toString等冗余代码,简化开发流程。

7.2.1 依赖引入
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
7.2.2 常用注解
注解作用
@Data生成getter/setter、toString、equals等方法
@Getter仅生成getter方法
@Setter仅生成setter方法
@NoArgsConstructor生成无参构造方法
@AllArgsConstructor生成全参构造方法

使用示例:

@Data@NoArgsConstructor@AllArgsConstructorpublicclassPerson{privateint id;privateString name;privateString password;}

8. 企业开发规范

遵循以下开发规范可提升代码可读性和维护性,符合企业级开发标准:

  1. 命名规范
    • 类名:大驼峰风格(如UserController)
    • 方法名、参数名、变量名:小驼峰风格(如getUserName)
    • 包名:全小写,多单词用点分隔(如com.example.demo.controller)
  2. 代码格式
    • 缩进:4个空格缩进,避免使用Tab
    • 注释:关键业务逻辑添加单行注释,类和方法添加文档注释
    • 空行:不同逻辑块之间添加空行,增强可读性
  3. 注解使用
    • 注解属性较多时,每个属性单独一行
    • 优先使用组合注解(如@RestController替代@Controller+@ResponseBody)

9. 参考资料与扩展学习

  1. 官方文档
  2. 工具资源

Read more

Flutter 三方库 tflite_web 端云协同 AI 引擎鸿蒙化高配适配:搭建异构计算 WebGL 后台管线并强力驱动 TensorFlow Lite-适配鸿蒙 HarmonyOS ohos

Flutter 三方库 tflite_web 端云协同 AI 引擎鸿蒙化高配适配:搭建异构计算 WebGL 后台管线并强力驱动 TensorFlow Lite-适配鸿蒙 HarmonyOS ohos

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 tflite_web 端云协同 AI 引擎鸿蒙化高配适配:搭建异构计算 WebGL 后台管线并强力驱动 TensorFlow Lite 轻量大模型推理内核运转 前言 在 OpenHarmony 构建混合架构(Hybrid App)的过程中,将 AI 能力直接下沉到客户端侧执行已成为主流趋势。虽然鸿蒙原生提供了强大的 AI 框架,但对于已有大量积累、且运行在 Flutter Web 容器中的应用而言,寻找一致性的端侧 AI 推理方案至关重要。tflite_web 库为基于 Flutter Web 的应用提供了调用 TensorFlow Lite 模型的能力。本文将调研其在鸿蒙 Web

By Ne0inhk
Flutter for OpenHarmony: Flutter 三方库 cached_query 为鸿蒙应用打造高性能声明式数据缓存系统(前端缓存终极方案)

Flutter for OpenHarmony: Flutter 三方库 cached_query 为鸿蒙应用打造高性能声明式数据缓存系统(前端缓存终极方案)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在进行 OpenHarmony 应用开发时,网络请求的响应速度直接决定了用户体验(体验 UX)。如果用户每次切换页面都必须等待加载动画,应用会显得非常低级。我们不仅需要处理异步数据请求,更需要一套精密的机制来解决以下痛点: 1. 自动缓存:第二次访问时应瞬间展示历史数据。 2. 过期失效(Stale-while-revalidate):在展示旧数据的同时,后台静默拉取新数据。 3. 无限滚动:简单地处理分页与数据追加内容逻辑。 cached_query 是一个类似于 Web 端 React Query 的 Dart 状态管理库。它专注于数据获取与同步,让你的鸿蒙应用具备顶级的数据缓存表现。 一、核心缓存驱动机制 cached_query 在内存与数据源之间建立了一层“智能感知”缓存。 数据过期/缺失 返回新数据 发射流

By Ne0inhk
【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题

【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题

【踩坑记录】使用 Layui 框架时解决 Unity WebGL 渲染在 Tab 切换时黑屏问题 在开发 Web 应用时,尤其是集成了 Unity WebGL 内容的页面,遇到一个问题:当 Unity WebGL 渲染内容嵌入到一个 Tab 中时,切换 Tab 后画面会变黑,直到用户点击黑屏区域,才会恢复显示。 这个问题通常是因为 Unity 渲染在 Tab 切换时被暂停或未能获得焦点所致。 在本文中,我们将介绍如何在使用 Layui 框架时,通过监听 Tab 切换事件并强制 Unity WebGL 渲染恢复,来解决这一问题。 1. 问题描述 当 Unity WebGL 内容嵌入到页面中的多个

By Ne0inhk
JavaScript 中 var、let、const 的核心区别与实战应用

JavaScript 中 var、let、const 的核心区别与实战应用

要理解 const、var、let 的区别,我们可以从 作用域、变量提升、可重复声明、可修改性 这几个核心维度展开,这些也是新手最容易混淆的点。 一、核心概念铺垫 首先明确两个基础概念,能帮你更好理解区别: * 函数作用域:变量只在声明它的函数内部可访问(var 是函数作用域)。 * 块级作用域:变量只在声明它的 {} 内部可访问(let/const 是块级作用域,{} 包括 if/for/while/ 普通代码块)。 * 变量提升:JS 引擎在执行代码前,会把变量声明 “提升” 到当前作用域顶部(但赋值不会提升)。 二、逐个拆解 + 对比 1. var(ES5 语法) var 是 ES5 中声明变量的方式,特性如下:

By Ne0inhk