SpringBoot快速上手
文章目录
- SpringBoot快速上手
- Maven
- 会出现的一个官方bug
- 创建完项目之后
- 常用的的三个功能
- 依赖管理
- Maven仓库
- 中央仓库
- 本地仓库
- 国内源配置
- 私服
- springboot项目创建
- 什么是spring
- spring boot项目的创建
- Hello World
- web服务器
- SpringMVC
- 什么是SpringWebMVC
- 什么是MVC
- SpringMVC
- 学习Spring web mvc
- 建立连接
- @RequestMapping
- 请求
- 指定请求方式
- 请求单个参数
- 请求多个参数
- 传递对象
- 参数重命名
- 设置参数为非必传的
- 传递数组
- 传递集合
- 传递`JSON`数据
- JSON与Javascript的关系
- JSON 优点
- 获取URL中的参数
- 上传文件
- 获取Cookie/Session
- Cookie
- Session
- Cookie和Session的区别
- 传统方式获取Cookie
- SpringBoot获取Cookie
- 传统方式获取Session
- SpringBoot获取Session
- 获取Header
- 传统获取Header
- springboot方式获取Header
- 响应
- 返回静态页面
- `@RestContraller` 和 `@Controller`的区别
- 路径问题
- 一个项目部署多个服务
- 返回数据@ResponseBody
- 返回HTML片段
- 返回JSON
- 设置状态码
- 设置Header
- 设置Content-Type
- 设置其他Header
- 案例
- 加法计算器
- 前端代码
- 后端代码
- 接口定义
- 用户登录
- 前端代码
- 后端代码
- 留言板
- 前端代码
- 后端代码
- lombok工具包介绍
- 图书管理系统
- 定义接口
- MOCK
- 应用分层
- 命名规范
- MVC和三层架构之间的关系
- SpringMVC小结
- 什么是springmvc
- @RequestMapping
- 请求
- 响应
- 注解总结
- Cookie和Session
学习流程介绍:
- spring boot
- springmvc
- spring framework
- mybatis
- spring 源码
Maven
项目管理工具,idea中将他嵌入进来了
- 项目构建、打包
- 依赖管理
会出现的一个官方bug
就是当你创建maven项目的时候会卡死
那么怎么办呢?
你只能先关闭原来项目,再重新去创建maven项目。
创建完项目之后
创建完maven项目之后,idea右边会出现一个maven的框
那么右键选择
就可以解决这个问题.
常用的的三个功能
clean
:清理class
文件(也就是清理缓存)
package
:打包
install
:在工作中常用于发布包到本地
依赖管理
通过poe.xml
依赖已经进来了.
-
会将当前的依赖引入到当前项目里面
-
Maven Helper
插件,可以查看依赖之间的关系
Maven仓库
仓库:
- 本地仓库
- 远程仓库
- 中央仓库
- 私有仓库
中央仓库
中央仓库
中央仓库查询会有一定的滞后性
本地仓库
需要自己配置噢
国内源配置
找到setting.xml
文件,在 mirrors 节点上,添加内容如下:
<mirror><id>aliyunmaven</id><mirrorOf>central</mirrorOf><name>阿⾥云公共仓库</name><url>http://maven.aliyun.com/nexus/content/groups/public/</url></mirror>
然后再设置好新项目的setting
.建议找一个存储空间大的盘,像我一样设置(如上图).因为随着时间推移,外卖做的项目的数量变多,本地仓库中的setting
文件的占用的内存也会越来越多.
还有就是建议命名不要用中文!
私服
企业开发中一些代码具有一定的私密性,所以企业会建立自己的私服(需要账号密码)
springboot项目创建
建议是申请教育版本的ideaa或者专业版的idea噢~
如果是社区版的idea,那么就需要你去下载spring
插件
别直接点击Install
,除非你钱多~
插件地址
什么是spring
spring是一个非常好用的框架,快 简单 安全
spring是一个家族产品,在面试中提到spring,大多是指spring家族.
而spring boot的诞生就是未来简化spring程序开发的
spring boot项目的创建
-
需要注意的是现在idea2023创建spring项目的时候,只有
jdk17 jdk21
,可以选择,这里我的解决办法是替换项目的源头,我们只知道IDEA页面创建Spring项目,其实是访问spring initializr去创建项目。故我们可以通过阿里云国服去间接创建Spring项目。将https://start.spring.io/或者http://start.springboot.io/替换为 https://start.aliyun.com/.即可解决这个问题. -
选择springboot版本,选择
2.X
版本,因为2.X
使用的是JDK8
,也不要选择snapshot
版本.(不稳定版本)snapshot 程序有问题的话,可以修改,重新发包
非 snapshot 是不能修改的,若需要修改,只能改版本号
-
此处的测试代码,和测试人员无关,是开发人员的测试代码,
开发人员先进行简单测试,测试完成之后再提交给测试人员.单元测试代码
-
项目启动
Hello World
创建HelloController
@RestController
public class HelloController {@RequestMapping("/hello")public String hello(){return "hello, SpringBoot";}
}
然后再网页中输入localhost:8080/hello
web服务器
常⻅的Web服务器有: Apache,Nginx, IIS, Tomcat, Jboss
等
SpringBoot 内置了Tomcat服务器, ⽆需配置即可直接运⾏
Tocmat默认端⼝号是8080, 所以我们程序访问时的端⼝号也是8080
SpringMVC
本小节将会了解到的:
- 学习常见的
Spring MVC Web
注解 - 了解
SPring MVC
来完成基础功能开发 - 了解
MVC
和三层架构的设计模式 - 掌握企业开发的命名规范
什么是SpringWebMVC
Spring Web MVC
是基于Servlet API
构建的原始Web框架,从一开始就包含在Spring
框架中。它的正式名称“Spring Web MVC”
来自其源模块的名称(Spring-webmvc)
,但它通常被称为"SpringMVC
".
什么是MVC
Model
模型:是应⽤程序的主体部分,⽤来处理程序中数据逻辑的部分
View
视图:指在应⽤程序中专⻔⽤来与浏览器进⾏交互,展⽰数据的资源
Controller
控制器:可以理解为⼀个分发器,⽤来决定对于视图发来的请求,需要⽤哪⼀个模型来处理,以及处理完后需要跳回到哪⼀个视图。即⽤来连接视图和模型
MVC
是一种思想,而Spring MVC
是MVC
的一种实现
SpringMVC
SpringMVC
项目的创建和上面创建SpringBoot
项目一样.
不过目前推崇的前后端分离已经不需要View
层了,于是乎:
学习Spring web mvc
- 建立连接
- 请求
- 响应
建立连接
@RequestMapping
类注解、方法注解
作用范围:
-
类
当一个类有多个注解的时候,这些注解没有先后顺序
类路径+方法路径
@RequestMapping("/user")// /可加可不加 但是我建议你加 @RestController public class UserController {@RequestMapping("/hello")public String hello(){return "hello";} }
此时访问路径:
[127.0.0.1:8080/user/hello](http://127.0.0.1:8080/user/hello)
-
方法上
@RestController public class UserController {@RequestMapping("/hello")public String hello(){return "hello";} }
请求方式是Get
还是Post
get
通过浏览器访问的方式为get
post
请求
指定请求方式
@RequestMapping("/user")
@RestController
public class UserController {@RequestMapping(value = "/hello",method = RequestMethod.GET)// 注解里,双引号的值会赋给"value"这个属性// 只有一个属性的时候,且属性名为value,可以省略public String hello(){return "hello";}
}
请求单个参数
@RequestMapping("/r1")public String r1(String name){return "接受到参数 name:" + name;}@RequestMapping("/r2")public String r2(int age){return "接受到参数 age:" + age;}
请求多个参数
@RequestMapping("/r3")public String r3(String name,Integer age){return "name:"+name+" "+"age:"+age;// 参数请求 顺序先后不分}
传递对象
// 创建userInfo
public class UserInfo {private Integer id;private String name;private Integer age;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "UserInfo{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}
}
@RequestMapping("/r4")public String r4(UserInfo user){return user.toString();}
参数重命名
@RequestParam
@RequestMapping("/r5")public String r4(@RequestParam("name") String username, Integer age){return "username: " + username+ ", age: " + age;}
@RequestParam(“name”) 从请求中获取 name 的参数,并且赋值给 username 参数 且默认这个参数是必传的
设置参数为非必传的
我们先看一下RequestParam
public @interface RequestParam {@AliasFor("name")String value() default "";@AliasFor("value")String name() default "";boolean required() default true;String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}
于是乎我们可以:将required
设置为false
@RequestMapping("/r5")public String r5(@RequestParam(value = "name", required = false) String username, Integer age){return "username: " + username+ ", age: " + age;}
传递数组
@RequestMapping("/r7")public String r7(String[]arr){return Arrays.toString(arr);}
传递集合
@RequestMapping("/r8")public String r8(@RequestParam("list") List<String> list){return list.toString();}
在Spring MVC中,
@RequestParam
注解用于从请求中提取参数值。@RequestParam("list") List<String> list
表示从请求中获取名为 “list” 的参数,并将其绑定到一个List<String>
类型的变量list
上。这种方式常用于接收前端传递的多个相同类型的参数,例如,前端通过 URL 或者表单提交将多个字符串参数传递给后端。通过将它们绑定到一个
List<String>
类型的参数上,你可以轻松地处理多个相同类型的参数。请求 URL 如下:
/r8?list=value1&list=value2&list=value3
通过上述的
@RequestParam("list") List<String> list
,Spring 将自动将这些值绑定到一个列表中,你可以在方法体内使用这个list
参数来访问传递的多个值。总的来说,这是一种方便的方式,用于处理请求中包含多个相同类型参数的场景。
在Web开发中,有时候我们需要从前端接收一组相同类型的参数。使用
List<String>
类型的参数绑定可以方便地处理这种情况,而不需要为每个参数定义一个独立的变量。考虑以下情景:
表单提交: 当用户通过表单提交多个相同类型的数据时,可以将这些数据绑定到一个
List<String>
中。例如,一个多选框(Checkbox)的多个选项。URL参数: 当通过URL传递多个相同类型的参数时,使用
List<String>
可以更清晰地表达意图。例如,/r8?list=value1&list=value2&list=value3
。RESTful风格的请求: 在RESTful风格的API中,有时需要从请求体或路径中接收多个相同类型的数据。
绑定到
List<String>
的好处包括:
代码简洁: 不需要为每个参数定义一个变量,通过一个
List
就可以容纳所有的值。可扩展性: 如果前端需要传递更多的相同类型的参数,代码不需要做太多修改。
清晰明了: 通过命名为
list
,表达了这是一组相同类型的数据。
传递JSON
数据
JSON与Javascript的关系
没有关系, 只是语法相似, js开发者能更快的上⼿⽽已, 但是他的语法本⾝⽐较简单, 所以也很好学
JSON 优点
-
简单易⽤: 语法简单,易于理解和编写,可以快速地进⾏数据交换
-
跨平台⽀持: JSON可以被多种编程语⾔解析和⽣成, 可以在不同的平台和语⾔之间进⾏数据交换和传输
-
轻量级: 相较于XML格式, JSON数据格式更加轻量级, 传输数据时占⽤带宽较⼩, 可以提⾼数据传输速度
-
易于扩展: JSON的数据结构灵活,⽀持嵌套对象和数组等复杂的数据结构,便于扩展和使⽤
-
安全性: JSON数据格式是⼀种纯⽂本格式,不包含可执⾏代码, 不会执⾏恶意代码,因此具有较⾼的安全性
public class JSONUtils {public static void main(String[] args) throws JsonProcessingException {ObjectMapper objectMapper = new ObjectMapper();UserInfo userInfo = new UserInfo();userInfo.setName("zhangsan");userInfo.setAge(18);userInfo.setId(12);// 对象转 JSONString s = objectMapper.writeValueAsString(userInfo);System.out.println(s);// JSON 转成 java 对象UserInfo userInfo1 = objectMapper.readValue(s,UserInfo.class);System.out.println(userInfo1);}
}
@RequestMapping("/r9")public String r9(@RequestBody UserInfo userInfo){return userInfo.toString();}
获取URL中的参数
@PathVariable
@RequestMapping("/r10/{articleId}")public String r10(@PathVariable Integer articleId){return "articleId:"+articleId;}
上传文件
@RequestPart
@RequestMapping("/r11")public String r11(@RequestPart MultipartFile file){return "获取上传文件:" + file.getOriginalFilename();}
@RequestMapping("/r11")public String r11(@RequestPart MultipartFile file) throws IOException {String fileName = file.getOriginalFilename();file.transferTo(new File("D:/temp/"+fileName));return "获取上传文件:" + file.getOriginalFilename();}
这段代码虽然也可以不加注解,但是建议还是将注解加上去
获取Cookie/Session
Cookie
HTTP 协议⾃⾝是属于 “⽆状态” 协议.
无状态协议:
默认情况下 HTTP 协议的客⼾端和服务器之间的这次通信, 和下次通信之间没有直接的联系.
但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的.
例如登陆⽹站成功后, 第⼆次访问的时候服务器就能知道该请求是否是已经登陆过了.
Session
会话:对话的意思
在计算机领域, 会话是⼀个客⼾与服务器之间的不中断的请求响应. 对客⼾的每个请求,服务器能够识
别出请求来⾃于同⼀个客⼾. 当⼀个未知的客⼾向Web应⽤程序发送第⼀个请求时就开始了⼀个会话.
当客⼾明确结束会话或服务器在⼀个时限内没有接受到客⼾的任何请求时,会话就结束了.
⽐如我们打客服电话
每次打客服电话, 是⼀个会话. 挂断电话, 会话就结束了
下次再打客服电话, ⼜是⼀个新的会话.
如果我们⻓时间不说话, 没有新的请求, 会话也会结束
服务器同⼀时刻收到的请求是很多的. 服务器需要清楚的区分每个请求是从属于哪个⽤⼾, 也就是属于哪个会话, 就需要在服务器这边记录每个会话以及与⽤⼾的信息的对应关系.
Session
是服务器为了保存⽤⼾信息⽽创建的⼀个特殊的对象.
Session的本质就是⼀个 “哈希表”, 存储了⼀些键值对结构. Key 就是SessionID, Value 就是⽤⼾信息(⽤⼾信息可以根据需求灵活设计).
SessionIsd
是由服务器生成的一个"唯一性字符串",从Session
机制的角度来看,这个唯一性字符串称为"Sessionld"
.但是站在整个登录流程中看待,也可以把这个唯一性字符串称为"token".
上述例子中的令牌ID,就可以看做是Sessionld
,只不过令牌除了ID之外,还会带一些其他信息,比如时间,签名等.
-
当⽤⼾登陆的时候, 服务器在 Session 中新增⼀个新记录, 并把 sessionId返回给客⼾端. (通过HTTP 响应中的 Set-Cookie 字段返回).
-
客⼾端后续再给服务器发送请求的时候, 需要在请求中带上 sessionId. (通过 HTTP 请求中的Cookie 字段带上).
-
服务器收到请求之后, 根据请求中的 sessionId在 Session 信息中获取到对应的⽤⼾信息, 再进⾏后续操作.找不到则重新创建Session, 并把SessionID返回
Session默认是保存在内存中的.如果重启服务器则Session数据就会丢失.
Cookie和Session的区别
在此之前我们可以举一个例子
学生入学
学校收集学生信息,姓名,班级,身份证号等等
那么学校该如何存储呢?
Number Name Age Attribute 1 张三 18 CS 2 李四 17 CS 3 王五 20 CS 学校存储信息之后,给学生发学生证
学生出入学校,使用学生证(就好比是
Cookie
)来证明身份但是,学生证可以造假,但是学校的教务系统的信息是造假不了的
于是乎:
Cookie
是可以造假的,但是Session
不行
-
用户提供账号和密码,服务器进行验证。
-
服务器验证通过,会把信息存储在
Session
中,把SessionId
返回给客户端(通过Set-Cookie
的方式) -
客户端收到响应,把
sessionID
存储在Cookie
中 -
后续的请求中,客户端带着
SessionID
去请求(带着Cookie
信息去请求)request.getSession
就是从Cookie
中获取SessionID
,并且根据SessionID
获取Session
信息
区别如下:
Cookie
是客户端保存用户信息的一种机制.Session
是服务器端保存用户信息的一种机制:Cookie
和Session
之间主要是通过Sessionld
关联起来的,Sessionld
是Cookie
和Session
之间的桥梁Cookie
和Session
经常会在一起配合使用.但是不是必须配合.- 完全可以用
Cookie
来保存一些数据在客户端.这些数据不一定是用户身份信息,也不一定是Sessionld
Session
中的sessionld
也不需要非得通过Cookie
/Set
-Cookie
传递,比如通过URL
传递
- 完全可以用
共同点:都是会话机制
Cookie
是客户端机制
Session
是服务器机制
Cookie
存储的信息由程序员而定
Session
也不一定必须存在Cookie
中
传统方式获取Cookie
@RestController
@RequestMapping("/request")
public class RequestController {@RequestMapping("/getCookie")public String getCookie(HttpServletRequest request) // 内置对象,有需要就加上,没需要就不加 需要几个就加几个{Cookie[] cookies = request.getCookies();// Arrays.stream(cookies).forEach(x->{
// System.out.println(x.getName()+":"+x.getValue());
// });// 等价于if (cookies != null){for(Cookie c:cookies){System.out.println(c.getName()+":"+c.getValue());}return "获取Cookies成功";}elsereturn "获取Cookies不成功";}
}
SpringBoot获取Cookie
@RequestMapping("/getCookie2")public String getCookie2(@CookieValue ("riyewuxiushi")String riyewuxiushi){return "riyewuxiushi"+riyewuxiushi;}
传统方式获取Session
@RequestMapping("/setSession")public String setSession(HttpServletRequest request){HttpSession session = request.getSession(); // 默认值为 truesession.setAttribute("userName","zhangsan");return "设置session成功";}@RequestMapping("/getSession")public String getSession(HttpServletRequest request){HttpSession session = request.getSession();String userName = (String) session.getAttribute("userName");return "登录用户:"+ userName;}
SpringBoot获取Session
@RequestMapping("/getSession2")public String getSession2(HttpSession session){ // 内置对象String userName = (String) session.getAttribute("userName");return "登录用户:"+ userName;}
@RequestMapping("/getSession3")public String getSession3(@SessionAttribute(value = "userName",required = false) String userName){return "登录用户:"+ userName;}
获取Header
传统获取Header
@RequestMapping("/getheader")public String getheader(HttpServletRequest request){String userAgent = request.getHeader("User-Agent");return "userAgent"+userAgent;}
springboot方式获取Header
@RequestMapping("/getheader2")public String getheader2(@RequestHeader("User-Agent")String userAgent){return "userAgent"+userAgent;}
响应
返回静态页面
@RequestMapping("/return")
//@RestController
@Controller
// 多个注解的时候 注解不分先后顺序
public class ReturnController {@RequestMapping("/r1")public String r1(){return "/index.html";}
}
@RestContraller
和 @Controller
的区别
@RestController
和 @Controller
是 Spring Framework 中用于标记类的注解,用于定义处理 HTTP 请求的控制器。它们之间有一些区别和联系。
区别:
- 返回值处理:
@Controller
通常用于创建传统的基于视图的 Web 应用程序,它的方法可以返回模型数据和视图名称,最终由视图解析器解析为具体的视图。而@RestController
则是用于创建 RESTful Web 服务的控制器,它的方法返回的是数据对象,会自动通过消息转换器将数据转为 JSON/XML 等格式,不会经过视图解析器。 - 默认行为:
@RestController
组合了@Controller
和@ResponseBody
注解的功能。@ResponseBody
注解表示方法的返回值将直接写入 HTTP 响应体中,而不是通过视图解析器解析为视图。因此,@RestController
类的每个方法都默认返回数据对象,而不是视图。 - 使用场景:
@Controller
适用于传统的基于视图的 Web 应用程序,例如使用 Thymeleaf、JSP 或者其他模板引擎渲染视图。@RestController
适用于构建 RESTful Web 服务,响应 JSON 或 XML 格式的数据。
联系:
- 标记作用:
@RestController
和@Controller
都是用于标记类的注解,将类声明为 Spring Framework 的组件,用于处理 HTTP 请求。 - 注解继承:
@RestController
是@Controller
注解的特殊化,可以认为是@Controller
的增强版本。@RestController
继承了@Controller
的所有功能,同时还提供了自动将方法返回值转换为数据格式的能力。
// @RestController 源码
@Target({ElementType.TYPE}) // 表示注解的范围
@Retention(RetentionPolicy.RUNTIME) // 注解的生命周期
@Documented //
// 上面三个是元注解:是可以注解到 其他注解 的注解
@Controller // ----> 这说明 RestContraller 是基于 Controller 实现的
@ResponseBody
public @interface RestController {@AliasFor(annotation = Controller.class)String value() default "";
}
@RestController = @Controller + @ResponseBody
@Controller
: 告诉Spring帮我们管理那些程序
@ResponseBody
:返回数据
路径问题
servlet
路径有项目名,是因为一个tomcat
下面可以部署多个项目,我们需要通过路径来进行区分spring
路径不需要有项目名,是因为springboot
内置了tomcat
,一个tomcat
下面就部署当前这一个项目- 如果部署多个项目,就启动多个
tomcat
一个项目部署多个服务
IDEA 2023.2新版如何将同一个项目开启多个
返回数据@ResponseBody
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
}
即可以修饰类,又可以修饰方法
修饰类:表示该类所有的方法 返回的是数据
修饰方法:表示该方法返回的是数据
@RequestMapping("/r1")public String r1(){return "/index.html";}@ResponseBody@RequestMapping("/r2")public String r2(){return "hello spring";}
返回HTML片段
@ResponseBody@RequestMapping("/r3")public String r3(){return "<h1>我是返回的片段</h1>";}
get
可以被缓存 幂等post
不可以被缓存
返回JSON
@ResponseBody@RequestMapping("/r4")public UserInfo r4(){UserInfo userInfo = new UserInfo();userInfo.setId(1);userInfo.setName("zhangsan");userInfo.setAge(19);return userInfo;}@ResponseBody@RequestMapping("/r5")public Map<String ,String> r5(){HashMap map = new HashMap();map.put("k1","v1");map.put("k2","v2");return map;}//@ResponseBody@RequestMapping("/r6")public String r6(){return "/a.js";}@RequestMapping("/r7")public String r7(){return "/b.css";}
设置状态码
@ResponseBody@RequestMapping("/r8")public String r8(HttpServletResponse response){response.setStatus(401);return "设置状态码成功";}
状态码的设置不影响页面的显示
设置Header
设置Content-Type
我们通过设置 produces属性的值, 设置响应的报头Content-Type
// @RequestMapping源码@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {String name() default "";@AliasFor("path")String[] value() default {};@AliasFor("value")String[] path() default {};RequestMethod[] method() default {};String[] params() default {};String[] headers() default {};String[] consumes() default {};String[] produces() default {};
}
value
: 指定映射的URL
method
: 指定请求的method
类型, 如GET
,POST
等
consumes
: 指定处理请求(request
)的提交内容类型(Content-Type
),例如application
/json
,text
/html
;
produces
: 指定返回的内容类型,仅当request
请求头中的(Accept
)类型中包含该指定类型才返回
Params
: 指定request
中必须包含某些参数值时,才让该⽅法处理
headers
: 指定request
中必须包含某些指定的header
值,才能让该⽅法处理请求
@ResponseBody@RequestMapping("/r9")public String r9(){return "123333";}@ResponseBody@RequestMapping(value = "/r9",produces = "application/json")public String r9(){return "123333";}
设置其他Header
设置其他Header的话, 需要使⽤Spring MVC的内置对象HttpServletResponse 提供的⽅法来进⾏设置
@ResponseBody@RequestMapping(value = "/r10",produces = "application/json")public String r10(HttpServletResponse response){response.setHeader("myHeader","myHeaderValue");return "设置Header成功";}
void setHeader(String name, String value) 设置⼀个带有给定的名称和值的 header. 如果 name已经存在, 则覆盖旧的值
案例
学习建议:
最开始学习的时候:小步慢跑
每次写少量的代码,就进行测试
不要一次把代码全部写完,一次性进行测试
随着对代码的熟悉,可以逐渐加大步伐
加法计算器
前端代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><form action="calc/sum" method="post"><h1>计算器</h1>数字1:<input name="num1" type="text"><br>数字2:<input name="num2" type="text"><br><input type="submit" value=" 点击相加 "></form>
</body></html>
后端接到需求的时候
- 需求评审
- 开发
- 接口的定义
- 开发
- 测试(自行测试,与测试人员无关)
- 联调(后端和前端联调)
- 提测(测试人员的工作)
- 上线
- 维护
- 下线
后端代码
接口定义
两个原则
- 看我需要什么(请求参数)
- 看对方需要什么(响应结果)
请求参数:参与计算的两个数字
响应结果:计算结果
/calc/sum
参数:
num1 , num2
返回结果:两者计算的数据
请求路径:calc/sum
请求⽅式:GET/POST
接⼝描述:计算两个整数相加
请求参数:
参数名 类型 是否必须 备注 num1 Integer 是 参与计算的第一个数 num2 Integer 是 参与计算的第二个数
响应数据:
Content-Type : text/html
@RestController
@RequestMapping("/calc")
public class CalcController {@RequestMapping("/sum")public String sum(Integer num1, Integer num2){Integer sum = num1 + num2;return "<h1>计算机计算结果: "+sum+"</h1>";}
}
问题可能出现的地方:
- 前端
- 后端
- 前后端交互
- 请求有没有发出去
- 后端有没有收到请求
用户登录
前端代码
// login.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>登录页面</title></head><body><h1>用户登录</h1>用户名:<input name="userName" type="text" id="userName"><br>密码:<input name="password" type="password" id="password"><br><input type="button" value="登录" onclick="login()"><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>function login() {$.ajax({type:"post",url:"/login/check",data:{userName:$("#userName").val(),password:$("#password").val()},success:function(result){if (result == true){// 用户名和密码正确location.href = "/index.html";// location.assign("index.html");// location.replace("index.html");}else{alert("用户名或密码错误");}}});}</script></body></html>
// index.html
<!doctype html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>用户登录首页</title></head><body>登录人: <span id="loginUser"></span><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>$.ajax({url:"/login/index",type:"get",success:function (result) {$("#loginUser").text(result);}});</script></body></html>
后端代码
用户验证:
/login/check
参数:
userName
password
响应:
用户和密码是否正确
true
false
获取登录的用户:
/login/index
参数:
无
响应:
登录的用户
@RequestMapping("/login")
@RestController
public class LoginController {@RequestMapping("/check")public boolean check(String userName, String password, HttpSession session){// 校验账号和密码是否为空
// if (userName == null || "".equals(userName) || password == null || "".equals(password)){
// return false;
// }if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){return false;}// 校验账号和密码是否正确// 模拟数据if("zhangsan".equals(userName) && "123456".equals(password)){ // 防止空指针,养成习惯 常量写在前面session.setAttribute("userName",userName);return true;}return false;}@RequestMapping("/index")public String index(HttpSession session){String userName = (String) session.getAttribute("userName");return userName;}
}
留言板
前端代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>留言板</title><style>.container {width: 350px;height: 300px;margin: 0 auto;/* border: 1px black solid; */text-align: center;}.grey {color: grey;}.container .row {width: 350px;height: 40px;display: flex;justify-content: space-between;align-items: center;}.container .row input {width: 260px;height: 30px;}#submit {width: 350px;height: 40px;background-color: orange;color: white;border: none;margin: 10px;border-radius: 5px;font-size: 20px;}</style></head><body><div class="container"><h1>留言板</h1><p class="grey">输入后点击提交, 会将信息显示下方空白处</p><div class="row"><span>谁:</span> <input type="text" name="" id="from"></div><div class="row"><span>对谁:</span> <input type="text" name="" id="to"></div><div class="row"><span>说什么:</span> <input type="text" name="" id="say"></div><input type="button" value="提交" id="submit" onclick="submit()"><!-- <div>A 对 B 说: hello</div> --></div><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script><script>// 页面加载时,显示留言信息// 从后端获取留言信息,显示在页面上$.ajax({type:"get",url:"/message/getList",success:function (messages) {for (var message of messages){var html = "<div>"+message.from+"对"+message.to+"说:"+message.message+"</div>";$(".container").append(html);}}});function submit(){//1. 获取留言的内容var from = $('#from').val();var to = $('#to').val();var say = $('#say').val();if (from== '' || to == '' || say == '') {return;}$.ajax({type:"post",url:"/message/publish",data:{from:from,to:to,message:say},success:function (result) {if (result == true){// 添加成功//2. 构造节点var divE = "<div>"+from +"对" + to + "说:" + say+"</div>";//3. 把节点添加到页面上$(".container").append(divE);//4. 清空输入框的值$('#from').val("");$('#to').val("");$('#say').val("");}else{alert("发表失败");}}});}</script></body></html>
后端代码
提交留言:用户输入留言信息的时候,后端需要将留言信息保存起来
URL:/message/publish
参数
from
:发表人to
:接收人message
:信息返回:提交成功/失败
true、false
展示留言:页面展示的时候,需要从后端获取到所有的留言信息
URL:/message/getList
参数
无
返回:全部的留言信息
List<MessageInfo>
lombok工具包介绍
-
新项目
创建项目的时候直接加入依赖
-
老项目
在poe.xml中引入依赖,去maven中央仓库找
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version><scope>provided</scope></dependency>
@Data public class MessageInfo {private String from;private String to;private String message;}
@Data
会自动生成get、set
方法idea会自己进行反编译
单独使用可以@Getter @Setter
注解 作用 @Getter 自动添加getter方法 @Setter 自动添加setter方法 @ToString 自动添加toString方法 @EqualsAndHashCode ⾃动添加 equals 和 hashCode ⽅法 @NoArgsConstructor 自动添加无参构造方法 @AllArgsConstructor 自动添加全属性构造方法,顺序按照属性的定义顺序 @NonNull 属性不能为null @RequiredArgsConstructor 自动添加必需属性的构造方法,final+@NonNull的属性为必需 @Data = @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor
+ @NoArgsConstructor
-
更快地引入依赖
下载这个就好啦~然后重启IDEA
使用方法:
package org.example.springmvc_demo;import lombok.Data;/*** @author 日夜无休时* @date 2024/1/29*/
@Data
public class MessageInfo {private String from;private String to;private String message;// 换一个新工具 lombook @Data
// public String getFrom() {
// return from;
// }
//
// public void setFrom(String from) {
// this.from = from;
// }
//
// public String getTo() {
// return to;
// }
//
// public void setTo(String to) {
// this.to = to;
// }
//
// public String getMessage() {
// return message;
// }
//
// public void setMessage(String message) {
// this.message = message;
// }}
package org.example.springmvc_demo;import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.List;/*** @author 日夜无休时* @date 2024/1/29*/
@RestController
@RequestMapping("/message")
public class MessageController {private List<MessageInfo>messageInfos = new ArrayList<>();@RequestMapping("/publish")public boolean publishMessage(MessageInfo messageInfo){if (!StringUtils.hasLength(messageInfo.getFrom())|| !StringUtils.hasLength(messageInfo.getTo())|| !StringUtils.hasLength((messageInfo.getMessage()))){return false;}// 暂时存放在内存中messageInfos.add(messageInfo);return true;}@RequestMapping("/getList")public List<MessageInfo> getList(){for (MessageInfo messageInfo : messageInfos){}return messageInfos;}
}
图书管理系统
定义接口
接口定义:
服务提供方:
提供什么服务
提供服务时,需要什么参数
处理之后,需要给对方什么响应
客户端角度:
- 我需要什么服务
- 服务端的参数 我是否有
- 对方给我提供的信息,能否满足我的需求
-
登录
URL: /user/login
参数:用户名和密码
userName
password
返回:
true:用户名和密码正确
false:用户名和密码错误
-
图书列表
URL:/book/getList
参数:无
返回:图书列表
List
MOCK
虚拟的、假的。开发的时候通常是几个团队并行开发,开发后需要进行测试(自测),如果测试时,依赖方还没完成开发,调用方就采用mock的方式,先进行测试。
应用分层
一种开发规范
三层架构(软件设计架构方式)
- 表现层:就是展示数据结果和接受用户指令的,是最靠近用户的一层
- 业务逻辑层:负责处理业务逻辑,里面有复杂业务的具体实现
- 数据层:负责存储和管理与应用程序相关的数据
命名规范
- 类名 大驼峰
- 变量名 小驼峰
MVC和三层架构之间的关系
共同点:
-
解耦(高内聚,低耦合)
模块内 关系尽量紧密(高内聚)
模块间 关系尽量关联低(低耦合)
比如说:公司与公司之间,关联应该越小越好,公司内部,员工应该团结
SpringMVC小结
什么是springmvc
spring web mvc
@RequestMapping
既是类注解,也是方法注解
访问的URL路径 = 类路径 + 方法路径
默认支持 get/post
,可以使用method
属性来限制请求方式
请求
- 请求当个参数
- 请求多个参数
- 请求参数为对象
- 对参数重命名
@RequestParam 默认是必传参数,设置 required = false 就是非必传
- 设置参数为非必传
- 请求参数为
JSON
@RequestBody
Cookie & Session
- 传递数组
- 传递集合
@RequestParam
- 获取Header
响应
- 返回静态页面
- 返回数据
@ResponseBody
- 返回
HTML
片段 - 返回
JSON
- 设置响应头(状态码、编码、其他
header
)
注解总结
- @RequestMapping: 路由映射
- @RequestParam: 后端参数重命名
- @RequestBody: 接收JSON类型的参数
- @PathVariable: 接收路径参数
- @RequestPart: 上传⽂件
- @ResponseBody: 返回数据
- @CookieValue: 从Cookie中获取值
- @SessionAttribute: 从Session中获取值
- @RequestHeader: 从Header中获取值
- @Controller: 定义⼀个控制器, Spring 框架启动时加载, 把这个对象交给Spring管理. 默认返回视图.
- @RestController: @ResponseBody + @Controller 返回数据
Cookie和Session
Cookie 和Session都是会话机制, Cookie是客⼾端机制, Session是服务端机制. ⼆者通过SessionId来关联. Spring MVC内置HttpServletRequest, HttpServletResponse两个对象. 需要使⽤时, 直接在⽅法中添加对应参数即可, Cookie和Session可以从HttpServletRequest中来获取, 也可以直接使⽤HttpServletResponse设置Http响应状态码.