大家好,我是晓星航。今天为大家带来的是 SpringMVC程序开发 相关的讲解!😀
官⽅对于 Spring MVC 的描述是这样的:
Spring Web MVC is the original web framework built on the Servlet API and has been includedin the Spring Framework from the very beginning. The formal name, “Spring Web MVC,”comes from the name of its source module ( spring-webmvc ), but it is more commonly known as “Spring MVC”.
引⽤来⾃: https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#spring-web
翻译为中⽂:
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从一开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来自其源模块的名称(Spring-webmvc),但它通常被称为“Spring MVC”
从上述定义我们可以得出两个关键信息:
然⽽要真正的理解什么是 Spring MVC?我们⾸先要搞清楚什么是 MVC?
SpringBoot 是创建Spring MVC项目的一种方式而已。
当前阶段,MVC的概念又发生了一些变化,后端开发人员不涉及前端页面的开发,所以
也就没有view层
所以view 又有了一层解释
之前返回的是视图,现在返回的是视图所需要的数据
MVC 是 Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构模式,它把软件系统分为模型、视图和控制器三个基本部分。
MVC 是⼀种思想,⽽ Spring MVC 是对 MVC 思想的具体实现。
总结来说,Spring MVC 是⼀个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架。既然是 Web 框架,那么当⽤户在浏览器中输⼊了 url 之后,我们的 Spring MVC 项⽬就可以感知到⽤户的请求。
现在绝⼤部分的 Java 项⽬都是基于 Spring(或 Spring Boot)的,⽽ Spring 的核⼼就是 Spring MVC。也就是说 Spring MVC 是 Spring 框架的核⼼模块,⽽ Spring Boot 是 Spring 的脚⼿架,因此 我们可以推断出,现在市⾯上绝⼤部分的 Java 项⽬约等于 Spring MVC 项⽬,这是我们要学 Spring MVC 的原因。
在创建 Spring Boot 项⽬时,我们勾选的 Spring Web 框架其实就是 Spring MVC 框架,如下图所示:
简单来说,咱们之所以要学习 Spring MVC 是因为它是⼀切项⽬的基础,我们以后创建的所有 Spring、Spring Boot 项⽬基本都是基于 Spring MVC 的。
学习 Spring MVC 我们只需要掌握以下 3 个功能:
对于 Spring MVC 来说,掌握了以上 3 个功能就相当于掌握了 Spring MVC。
请求,主要学习如何传递参数
1.传递单个参数
2.多个参数
3.对象
4.数组/集合…
Spring MVC 项⽬创建和 Spring Boot 创建项⽬相同(Spring MVC 使⽤ Spring Boot 的⽅式创建), 在创建的时候选择 Spring Web 就相当于创建了 Spring MVC 的项⽬。
在 Spring MVC 中使⽤ @RequestMapping 来实现 URL 路由映射,也就是浏览器连接程序的作⽤。 接下来要实现的功能是访问地址:
http://127.0.0.1:8080/sayhello,能打印“hello,spring mvc”信息。
路径也可以写多层
此时我们访问sayhello就要先访问hello再访问sayhello文件夹
使用postman进行访问
@RequestMapping 支持get和post
Spring MVC 可以基于 Spring Boot 创建,也就是创建⼀个 Spring Boot 项⽬,勾选上 Spring Web 模块即可,如下图所示:
接下来,创建⼀个 UserController 类,实现⽤户到 Spring 程序的互联互通,具体实现代码如下:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller // 让 spring 框架启动时,加载 @ResponseBody // 返回⾮⻚⾯数据 @RequestMapping("/user") // 路由器规则注册 public class UserController { // 路由器规则注册 @RequestMapping("/hi") public String sayHi(){ return "Hi,Spring MVC.
"; } }
这样实现之后,当访问地址:http://localhost:8080/user/hi 时就能打印“hello,spring mvc”的信息了。
@RequestMapping 是 Spring Web 应⽤程序中最常被⽤到的注解之⼀,它是⽤来注册接⼝的路 由映射的。
路由映射:所谓的路由映射指的是,当⽤户访问⼀个 url 时,将⽤户的请求对应到程序中某个类 的某个⽅法的过程就叫路由映射。
@RequestMapping 基础使⽤:
import com.example.demo.model.Person; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/p") public class PersonController { @RequestMapping("/index") public Object index(Person person){ // 获取参数 System.out.println(person.getName() +":"+ person.getPassword()); // 执⾏业务... return "/index.html"; } }
@RequestMapping 即可修饰类,也可以修饰⽅法,当修饰类和⽅法时,访问的地址是类 + ⽅ 法。
@RequestMapping 也可以直接修饰⽅法,代码实现如下:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @ResponseBody // 定义返回的数据格式为⾮视图(text/html) public class UserController { @RequestMapping("/hi") public String sayHi(){ return "Hi,Spring MVC.
"; } }
⽅法地址:http://localhost:8080/hi
使⽤ PostMan 测试⼀下,默认情况下使⽤注解 @RequestMapping 是否可以接收 GET 或 POST 请 求?
指定 GET/POST ⽅法类型
我们可以显示的指定 @RequestMapping 来接收 POST 的情况,如下所示:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller @ResponseBody // 定义返回的数据格式为⾮⻚⾯ public class UserController { @RequestMapping(value = "/hi",method= RequestMethod.POST) public String sayHi(){ return "Hi,Spring MVC.
"; } }
只允许POST请求结果图:
如果我们更改代码指定为只允许GET请求:
get 请求的 3 种写法:
// 写法1 @RequestMapping("/index") // 写法2 @RequestMapping(value = "/index",method = RequestMethod.GET) // 写法3 @GetMapping("/index")
post 请求的 2 种写法:
// 写法1 @RequestMapping(value = "/index",method = RequestMethod.POST) // 写法2 @PostMapping("/index")
在 Spring MVC 中可以直接⽤⽅法中的参数来实现传参,⽐如以下代码:
@RequestMapping("/param") @RestController public class ParamController { public String m1(String name) { return "接收到的参数name:" + name; } }
在 postman 中访问⽅法:
需要名称一样
底层逻辑:从请求的参数中,获取参数名为name的值,并给name赋值
@RequestMapping("/param") @RestController public class ParamController { @RequestMapping("/m1") public String m1(String name) { return "接收到的参数name:" + name; } @RequestMapping("/m2") public String m2(String name,Integer age) { return "接收到的参数name:" + name + "age:" + age; } }
在 postman 中访问⽅法:
直接发送,参数的顺序可以调换
我们再看一个例子,这里我们将int的包装类型(Integer)换成int会发生什么呢?
可以看到,我们再运行启动这段代码时发什么错误,错误信息大致为age这个变量不是包装类,返回类型为null时会发生错误
如果使用基本类型,必须要传值,不传值会报错。
所以开发时,建议使用包装类,比如Integer,可以区分0和null。
并且 Spring MVC 可以⾃动实现参数对象的赋值,⽐如 Person 对象:
import lombok.Data; @Data public class Person { private int id; private String name; private String password; }
传递对象代码实现:
@RequestMapping("/m4") public String m4(Person person) { return "接收到的参数name:" +person.toString(); }
前端访问:
开发中,接口的参数通常定义为对象。
@RequestMapping("/m3") public Object method_3(String name, String pwd) { System.out.println("name 参数:" + name); System.out.println("pwd 参数:" + pwd); return "/index.html"; }
重要说明:当有多个参数时,前后端进⾏参数匹配时,是以参数的名称进⾏匹配的,因此参数的位置 是不影响后端获取参数的结果。
某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致,⽐如前端传递了⼀个 time 给后端,⽽后端⼜是有 createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现 这种情况,我们就可以使⽤ @RequestParam 来重命名前后端的参数值。
具体示例如下,后端实现代码:
@RequestMapping("/m4") public String m4(@RequestParam("name") String username) { return "接收到的参数name:" + username; }
前端访问地址:
我们这里结果发生错误是因为我们前端给的参数为name,而我们此时使用的参数时username因为会报错400
在idea的报错信息亦是如此,name通过方法parameter命名为类型的值不存在
如果此时我们修改一下,将参数name传过去,那么此时我们的username就可以接收到参数值了
上⾯的列⼦,如果我们是前端传递⼀个⾮ time 的参数,就会出现程序报错的情况,如下图所示:
这是因为后端已经声明了前端必须传递⼀个 time 的参数,但是前端没有给后端传递,我们查看 @RequestParam 注解的实现细节就可以发现端倪,注解实现如下:
⾮必传参数设置
如果我们的实际业务前端的参数是⼀个⾮必传的参数,我们可以通过设置 @RequestParam 中的 required=false 来避免不传递时报错,具体实现如下:
@RequestMapping("/m4") public Object method_4(@RequestParam(value = "time", required = false) Stri ng createtime) { System.out.println("时间:" + createtime); return "/index.html"; }
postman查看结果:
此时我们传输的结果就不会报错,而转为给一个默认值null
后端接收代码:
@RequestMapping(value = "/m5", method = RequestMethod.POST) public Object method_5(@RequestBody Person person) { System.out.println("Person:" + person); return "redirect:/index.html"; }
尝试去除掉 @RequestBody 试试。
获取单个URL
@RequestMapping("/m9/{userId}") public String m9(@PathVariable Integer userId) { return "usrId:" + userId; }
注意此时参数要加 @PathVariable 我们才能成功获取到URL
前端⽅法地址:
获取多个值:
@RequestMapping("/m9/{userId}/{name}") public String m9(@PathVariable Integer userId,@PathVariable String name) { return "usrId:" + userId + ",name:" + name; }
注意此时参数要加 @PathVariable 我们才能成功获取到URL
前端⽅法地址:
重命名后:
要求:主文件夹里的name和下面重命名前括号中的name要一致,@PathVariable 后面为重命名后的变量名
@RequestMapping("/m10") public String m10(@RequestPart MultipartFile file) { System.out.println(file.getOriginalFilename()); return "success"; }
postman传输结果:
idea中控制台也打印了刚才上传图片的信息:
将上传图片保存到电脑本地:
我们新增的代码便会将我们选中的文件上传并保存到我们本地的 D:/EDU/ 中
注意此时的EDU文件夹下之后两个文件
我们选择cat.webp并通过postman发送给m10响应,然后找到EDU文件夹查看
此时我们发现EDU文件夹下多了一个cat.webp文件,证明我们文件上传保存到本地已成功实现
获取项⽬⽬录的⼏种⽅式:
ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX).getPath(); new ClassPathResource("").getFile().getAbsolutePath(); ClassUtils.getDefaultClassLoader().getResource("").getPath(); ResourceUtils.getFile("classpath:static/").getPath();
练习:上传⼀个图⽚到本机的某个⽬录。
Cookie和Session的区别:
获取 Request 和 Response 对象
@RequestMapping("/getCookie") public String getCookie(HttpServletRequest request, HttpServletResponse response) { Cookie[] cookies = request.getCookies(); // for (Cookie cookie : cookies) { // System.out.println(cookie.getName()+":"+cookie.getValue()); // } if (cookies != null) { Arrays.stream(cookies).forEach(cookie -> { System.out.println(cookie.getName()+":"+cookie.getValue()); }); } return "获取cookie成功"; }
获取session
何为session?
答:在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。
第一种获取方法:
@RequestMapping("/getSession") public String getSession(HttpServletRequest request) { HttpSession session = request.getSession(false); if (session != null) { String username = (String)session.getAttribute("username"); return "登录用户:"+username; } return "session 为空"; }
第二种获取方法:
@RequestMapping("/getSession2") public String getSession2(@SessionAttribute(required = false) String username) { return "username:"+username; }
我们先setSession设置Session
再使用getSession2来获取设置完毕后的Session
第三种获取方法:
@RequestMapping("/getSession3") public String getSession3(HttpSession session) { String username = (String)session.getAttribute("username"); return "登录用户:"+username; }
我们先setSession设置Session,再使用getSession3来获取设置完毕后的Session
成功拿到我们的cookie,并从cookie中解析得到了我们设置好的用户名
传统获取 header/cookie
@RequestMapping("/param10") @ResponseBody public String param10(HttpServletResponse response, HttpServletRequest requ est) { String name = request.getParameter("name"); // 获取所有 cookie 信息 Cookie[] cookies = request.getCookies(); String userAgent = request.getHeader("User-Agent"); return name + ":"+userAgent; }
简洁的获取 Cookie—@CookieValue
@RequestMapping("/cookie") @ResponseBody public String cookie(@CookieValue("bite") String bite) { return "cookie:" + bite; }
简洁获取 Header—@RequestHeader
@RequestMapping("/header") @ResponseBody public String header(@RequestHeader("User-Agent") String userAgent) { return "userAgent:"+userAgent; }
获取Header
Header:标头 (header) 是服务器以HTTP协议传HTML资料到浏览器前所送出的字串,在标头与 HTML 文件之间尚需空一行分隔。
第一种获取方法:
@RequestMapping("/getHeader") public String gerHeader(HttpServletRequest request) { String userAgent = request.getHeader("User-Agent"); return "userAgent" + userAgent; }
第二种获取方法:
@RequestMapping("/getHeader2") public String gerHeader2(@RequestHeader("User-Agent")String userAgent) { return "userAgent" + userAgent; }
@RequestMapping("/m5") public String m5(String[] arrayParam) { return "接收到的参数arrayParam:" + Arrays.toString(arrayParam) + ",长度:" + arrayParam.length; }
传递数组
当我们请求中,同一个参数有多个时,浏览器就会帮我们给封装成一个数组
更改一下代码,使用List来接收数组
@RequestMapping("/m6") public String m6(ListlistParam) { return "接收到的参数listParam:" + listParam + ",长度:" + listParam.size(); }
发现错误500,表示服务端发生错误
5开头的通常值服务端发生错误
4开头的通常值客户端发生错误
如果看到5开头的错误,第一反应去看后端日志
后端日志从下往上看,一段一段的看
先看最后一段的首行
看完后端代码后发现缺少数组重命名:
于是加上@RequestParam再次启动idea
成功接收到我们的参数,以及长度
JSON: JavaScript Object Notation [JavaScript 对象表示法]
JSON是一种轻量级的数据交互格式,它基于 ECMAScript(欧洲计算机协会制定的is规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。–百度百科
简单来说:JSON就是一种教据格式,有自己的格式和语法,使用文本表示一个对象或数组的信息,因此JSON本质是字符串,主要负责在不同的语言中数据传递和交换,
类似于:
- 国际通用语言-英语
- 中国56个民族不同地区的通用语言-普通话
有自己的语法,其他语言也认识.
JSON与Javascript的关系
没有关系,只是语法相似,is开发者能更快的上手而已,但是他的语法本身比较简单,所以也很好学
JSON 是一个字符串,其格式非常类似于 JavaScrip t 对象字面量的格式
我们先来看一段JSON数据
{ "squadname"; "Super hero squad", "homeTown":“Metro city”. "formed": 2016, "secretBase":“super tower”, "active": true. "meabers":[{ "name":"Holecule Man", "age": 29, "secretidentity": "Dan Jukes”. powers"; ["Radiation resistance", "Turning tiny", "Radiation blast"] },{ "name": "Madane uppercut”, age": 39 "secretIdentity":"Jane Wilson", powers": ["Million tonne punch", "Damage resistance", "superhuman reflexes"] },{ "name": "eternal flane", 2ge”: 1088800 secretIdentity":"Unknown”, "powers": ["Immortality,"Heat Imunity", "Inferno", "Teleportation","Interdine }] }
也可以压缩表示:
{"squadhame":"Super hero squad","homeToun":"Metro City","formed":2016,"secretBase":"Super tower","active";true,"members":[{"nane";"Molecule Man","age";29,"secretidentity";"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretidentity":"Jane Wilson","powers":["million tonne punch","Damage resistance",“superhuman reflexes"]}.{"name":"eternal Flame","age":1000000,"secretidentity":"unknown","powers":["Iortality","Heat Immunity,"Inferno”,"Teleportation”,"Interdimensional travel”]}]}
和上面描述的数据一样,只不过上面的进行了格式化,更易读
JSON的语法:
1.数据在键值对(Key/Value) 中
2.数据由逗号 。分隔
3.对象用 表示
4.数组用[] 表示
5.值可以为对象。也可以为数组,数组中可以包含多个对象
JSON的两种结构
1.对象:大括号{}保存的对象是一个无序的 键值对 集合,一个对象以左括号 { 开始,右括号 } 结束。每个“键”后跟一个冒号 :,键值对使用逗号,分隔
2.数组: 中括号 [] 保存的数组是值(value) 的有序集合,一个数组以左中括号 [ 开始,右中括号 ] 结束,值之间使用逗号,分隔
所以,以下都是合法的JSON数据
{"name":"admin","age":18} ["hello",3.1415,"json"] [{"name":"adnin","age":18},{"nane":"root","age":16},{"name":"3k=","age":20}]
可以使用在线JSON格式化工月来讲行校哈和书写: 在线JSON校验格式化工 (Be JSON)
JSON本质上是一个字符串,通过文本来存储和描述数据
Spring MVC框架也集成了JSON的转换工具,我们可以直接使用,来完成JSON字符串和Java对象的互转
本质上是jackson-databind提供的功能,Spring MVC框架中已经把该工具包引入了进来,咱们直接使用即可,如果脱离Spring MVC使用,需要引入相关依赖
com.fasterxml.jackson.corec jackson-databind 2.13.5 JSON的转换工具包有很多,jackson-databind只是其中的一种
public class Jsonutils [ private static objectrapper objectmapper = new objectmapper(); public static void main(string[] args) throws JsonprocessingException { Person person = new person(): person.setId(5); person.setName("zhangsan"); person.setPassword(“123456”); //对象转为JSON字符串 String jsonstr = objectMapper .writevalueAsstring(person); System.out.println("JSON字符串为:“+jsonStr); //JSON字符串转为对象 Person p = objectMapper .readvalue(jsonstr,Person.class); System.out.println("转换的对象id:"+p.getId()+",name:"+p.getName()+",password:"+p.getPa } }
使用ObjectMapper 对象提供的两个方法,可以完成对象和JSON字符中的互转
writeValueAsString: 把对象转为JSON字符串
readValue: 把字符申转为对象
JSON优点
1.简单易用: 语法简单,易于理解和编写,可以快速地进行数据交换
2.跨平台支持: ]SON可以被多种编程语言解析和生成,可以在不同的平台和语言之间进行数据交换和传输
3.轻量级: 相较于XML格式,JSN数据格式更加轻量级,传输数据时占用带宽较小,可以提高数据传输速度
4.易于扩展: JSON的数据结构灵活,支持嵌套对象和数组等复杂的数据结构,便于扩展和使用
5.安全性:JSON数据格式是一种纯文本格式,不包含可执行代码,不会执行恶意代码,因此只有较高的安全性
基于以上特点,JSON在Web内用程序中被广泛使用,如前后端数据交互、API接口数据传输等
接收JSON对象,需要使用 @RequestBody 注解
RequestBody; 请求正文,意思是这个注解作用在请求正文的数据绑定,请求参数必须在写在请求正文中
后端实现:
@RequestMapping("/m8") public String m8(@RequestBody Person person) { return "接收到的数据person:" + person.toString(); }
使用Postman来发送ison请求参数:
通过上⾯的学习我们知道,默认请求下⽆论是 Spring MVC 或者是 Spring Boot 返回的是视图 (xxx.html),⽽现在都是前后端分离的,后端只需要返给给前端数据即可,这个时候我们就需要使⽤ @ResponseBody 注解了。
@ResponseBody可以修饰 类 也可以修饰 方法
创建前端⻚⾯ index.html
hello,spring mvc Hello,Spring MVC.
创建控制器 controller:
import com.example.demo.model.Person; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/p") public class PersonController { @RequestMapping("/index") public Object index(){ // 执⾏业务... // 返回view -> index.html return "/index.html"; } }
和返回数据一样,返回的数据中包含html标签的话,会直接被浏览器解析
@Controller public class ReturnController { @RequestMapping("/index") public String returnIndex() { return "/index.html"; } }
@Controller public class ReturnController { @ResponseBody @RequestMapping("/returnData") public String returnData() { return "返回视图需要的数据"; } }
返回代码片段
@Controller public class ReturnController { @ResponseBody @RequestMapping("/returnHtml") public String returnHtml() { return "返回HTML代码片段
"; } }
练习:实现计算器功能。
可使⽤ postman 传递参数,或使⽤ form 表单的⽅式提交参数。 前端⻚⾯:
计算器示例
controller 代码:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @ResponseBody @Controller @RequestMapping("/calc") public class CalcController { @RequestMapping("/sum") public String sum(Integer num1,Integer num2){ return String.format("计算的结果是:%d
返回",num1+num2); } }
@Controller public class ReturnController { @ResponseBody @RequestMapping("/returnJson") public Person returnJson() { Person person = new Person(); person.setId(1); person.setName("qiqi"); person.setAge(7); return person; } }
练习:实现登录功能,前端使⽤ ajax,后端返回 json 给前端
后端代码:
@RequestMapping(value = "/login") @ResponseBody public HashMaplogin(String username, String password){ HashMap res = new HashMap<>(); int succ = 200; if(username!=null && password!=null && username.equals("admin") && password.equals("admin")){ res.put("msg","登录成功"); }else{ res.put("msg","登录失败"); } res.put("succ",succ); return res; }
前端代码:
Document 登录
⽤户:
密码:
Spring MVC会根据我们方法的返回结果自动设置响应状态码,程序员也可以手动指定状态码,通过Spring MVC的内置对象 HttpServletResponse 提供的方法来进行设置。
@ResponseBody @RequestMapping("/setStatus") public String setStatus(HttpServletResponse response) { response.setStatus(401);//通常表示没有登录 return "设置状态码"; }
状态码不影响页面的展示
Header:标头 (header) 是服务器以HTTP协议传HTML资料到浏览器前所送出的字串,在标头与 HTML 文件之间尚需空一行分隔。
@ResponseBody @RequestMapping(value = "/r1",produces = "application/json;charset=utf-8") public String r1(HttpServletResponse response) { response.setStatus(401);//通常表示没有登录 return "{'OK':1}"; }
forward VS redirect
return 不但可以返回⼀个视图,还可以实现跳转,跳转的⽅式有两种:
请求转发和重定向的使⽤对⽐:
// 请求重定向 @RequestMapping("/index") public String index(){ return "redirect:/index.html"; } // 请求转发 @RequestMapping("/index2") public String index2(){ return "forward:/index.html"; }
举例说明 forward 和 redirect
forward(请求转发)和 redirect(请求重定向)的区别,举例来说,例如,你告诉你妈妈,你想吃辣 条,如果你妈妈,说好,我帮你去买,这就是 forward 请求转发;如果你妈妈让你⾃⼰去买,那么就是 请求 redirect 重定向。
“转发”和“重定向”理解:在中国官⽅发布的内容越少事也越⼤, “转发”和“重定向”也是⼀样:字越 少,责任越⼤ 。转发是服务器帮转的,⽽重定向是让浏览器重新请求另⼀个地址。
forward 和 redirect 具体区别如下:
请求转发 forward 导致问题演示
请求转发如果资源和转发的⻚⾯不在⼀个⽬录下,会导致外部资源不可访问,演示示例如下。 controller 示例代码:
@Controller @RequestMapping("/user") public class UserController { @RequestMapping(value = "/index") public String sayHi(){ return "forward:/index.html"; } }
程序的⽬录如下:
程序的执⾏结果如下:
尝试将转发 foward 换成重定向 redirect,如下代码所示:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping("/user") public class UserController { @RequestMapping(value = "/index") public String sayHi(){ return "redirect:/index.html"; } }
⻚⾯就可以正常获取到外部资源 js 了。
@ResponseBody 返回的值如果是字符会转换成 text/html,如果返回的是对象会转换成 application/json 返回给前端。
@ResponseBody 可以⽤来修饰⽅法或者是修饰类,修饰类表示类中的所有⽅法都会返回 html 或者 json,⽽不是视图。
@RestController = @Controller + @ResponseBody
Document
接口定义:
请求路径:calc/sum 请求方式:GET/POST 接口描述:计算两个整数相加
请求参数:
实例:num1=5&num2=3
响应数据:
Content-Type: text/html 响应内容:计算机结算结果:8
服务器给浏览器返回计算的结果
后端:
package org.example.demo.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RequestMapping("/calc") @RestController public class CalcController { @RequestMapping("/sum") public String sum(Integer num1,Integer num2){ Integer sum = num1 + num2; return "计算机结果为:" + sum; } }
1.先定位前端还是后端
通过日志
1)前端:F12 看控制台
2)后端:接口,控制台日志
index.html
用户登录首页 登录人:
login.html
登录页面 用户登录
用户名:
密码:
package org.example.demo.controller; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Created with IntelliJ IDEA * Description * User: 晓星航 * Date: 2024 -03 -08 * Time: 11:50 */ @RequestMapping("/user") @RestController public class UserController { @RequestMapping("/login") public Boolean login(String userName, String password, HttpSession session) { //校验参数合法性 // if (userName == null || userName.length() == 0 || password == null || password.length() == 0) { // return false; // } //若username或password中任一一个为空就会返回false,加上!后返回true if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) { return false; } //进行用户名和密码校验 if ("admin".equals(userName) && "admin".equals(password)) { //设置Session session.setAttribute("username","admin"); return true; } return false; } @RequestMapping("/getUserInfo") public String getUserInfo(HttpServletRequest request) { //从Session中获取登录用户 HttpSession session = request.getSession(false); String username = null; if (session != null) { username = (String) session.getAttribute("username"); } return username; } }
messageWall.html:
留言板 留言板
输入后点击提交, 会将信息显示下方空白处
谁:对谁:说什么:
MessageInfo.java (接口)
import lombok.Data; import lombok.Getter; import lombok.Setter; import lombok.ToString; import java.util.Date; @Data public class MessageInfo { private String from; private String to; private String message; private Date CreteTime; }
MessageController.java
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; /** * Created with IntelliJ IDEA * Description * User: 晓星航 * Date: 2024 -03 -14 * Time: 19:48 */ @RestController @RequestMapping("/message") public class MessageController { private ListmessageInfos = new ArrayList<>(); @RequestMapping("/publish") public Boolean publishMessage(MessageInfo messageInfo) { //进行参数校验 StringUtils.hasLength()如果为空返回false,加上!后 如果为空会整体返回true if (!StringUtils.hasLength(messageInfo.getFrom()) || !StringUtils.hasLength(messageInfo.getTo()) || !StringUtils.hasLength(messageInfo.getMessage())) { return false; } //添加留言 messageInfos.add(messageInfo); return true; } @RequestMapping("/getMessageInfo") public List getMessageInfo() { return messageInfos; } }
引入lombok包的意义是可以避免在每一个接口中都需要写get和set方法,引入完毕后我们就可以直接使用方法来使用接口中的成员变量了。
引入之后,使用maven刷新一下,我们引入的包就下载完毕了
然后在我们的自定义接口类中加上 @Data ,此时这个注解会帮我们自动编写get和set方法
如果我们只想部分方法可以使用get和set方法
此时我们可以在我们想使用的成员变量上加上 @Getter 和 @Setter 注解来只针对我们部分成员变量进行get方法和set方法的创建
首先我们要安装一个新的插件
在pom.xml文件中右键,点击Generate
选择第一个Edit Starters
选择OK
找到Lombok,点击添加并OK确认即可完成添加Lombok包的功能
@Data
@ToString
如果代码出问题了
删除没用的代码
login.html:
Document 登陆
用户名密码
book_list.html:
图书列表展示
字段说明:
验证后端接口
BookInfo.java:
package org.example.book; import lombok.Data; import java.math.BigDecimal; /** * Created with IntelliJ IDEA * Description * User: 晓星航 * Date: 2024 -03 -15 * Time: 11:30 */ @Data public class BookInfo { private Integer id; private String bookName; private String author; private Integer count; private BigDecimal price; //定价使用BigDecimal使得精度更准确 private String publish; private Integer status;//1-可借阅,2-不可借阅 private String statusCN; }
UserController.java:
package org.example.book; import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Created with IntelliJ IDEA * Description * User: 晓星航 * Date: 2024 -03 -15 * Time: 11:27 */ @RequestMapping("/user") @RestController public class UserController { @RequestMapping("/login") public Boolean login(String userName, String password, HttpSession session){ //校验参数 if (!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){ return false; } //验证账号密码是否正确 //这种写法导致的问题 如果userName 为null,则会报空指针异常 // if (userName.equals("admin") && password.equals("admin")) { // // } if ("admin".equals(userName) && "admin".equals(password)) { //账号密码正确 //存Session session.setAttribute(“username”,username); 是将username保存在session中 session.setAttribute("userName",userName); return true; } return false; } }
BookController.java:
package org.example.book; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Random; /** * Created with IntelliJ IDEA * Description * User: 晓星航 * Date: 2024 -03 -15 * Time: 11:27 */ @RequestMapping("/book") @RestController public class BookController { @RequestMapping("/getBookList") public ListgetBookList() { //1.获取图书数据 //2.对图书数据进行处理 //3.返回数据 //mock 表示虚拟的,假数据 List bookInfos = mockData(); for (BookInfo bookInfo : bookInfos) { if (bookInfo.getStatus() == 1) { bookInfo.setStatusCN("可借阅"); } else { bookInfo.setStatusCN("不可借阅"); } } return bookInfos; } private List mockData() { List bookInfos = new ArrayList<>(15); for (int i = 0; i < 15; i++) { BookInfo bookInfo = new BookInfo(); bookInfo.setId(i); bookInfo.setBookName("图书"+i); bookInfo.setAuthor("作者"+i); bookInfo.setCount(new Random().nextInt(200)); bookInfo.setPrice(new BigDecimal(new Random().nextInt(100))); bookInfo.setPublish("出版社"+i); bookInfo.setStatus(i%5==0?2:1); bookInfos.add(bookInfo); } return bookInfos; } }
登录页面:
列表页:
应用分层的好处
文件夹分层
代码分层
@RestController = @Controller + @ResponseBody
@RestController无法返回指定页面,
@Controller可以返回指定页面。
@RestController可以直接返回数据,
而@Controller需要@ResponseBody的辅助才能返回数据。
每一个spring项目开头必带的注释
此时这里的我们要访问m1下的内容,我们需要输入: http://127.0.0.1:8080/param/m1
官⽅ API:https://docs.spring.io/springframework/docs/current/reference/html/web.html#mvc-ann-requestmapping
类名使用大驼峰风格,但以下情形例外: DO/BO/DTO/VO/AO
方法名、参数名、成员变量、局部变量统一使用小驼峰风格
包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词
常见命名命名风格介绍
大驼峰: 所有单词首字母都需要大写,又叫帕斯卡命名法,比如: UserController
小驼峰: 除了第一个单词,其他单词首字母大写,比如: userController
蛇形: 用下划线()作用单词间的分隔符,一般小写,又叫下划线命名法,比如: user_control
串形: 用短横线(-)作用单词间的分隔符,又叫脊柱命名法,比如: user-controller
类名使用大驼峰
变量名使用小驼峰
数据库,字段命名用蛇形
学习Spring MVC,其实就是学习各种Web开发需要用的到注解
Cookie 和Session都是会话机制,Cookie是客户端机制,Session是服务端机制.二者通过SessionId来关联,Spring MVC内置HttpServletRequest,HttpServletResponse两个对象,需要使用时,直接在方法中添加对应参数即可,Cookie和Session可以从HttpServletRequest中来获取,也可以直接使用HttpServletResponse设置Http响
状态码
Java EE学习阶段会涉及较多工具,插件的学习,来帮助我们提高开发效率,比如Postman,lombok,EditStarter
pps-1712723849768)]
官⽅ API:https://docs.spring.io/springframework/docs/current/reference/html/web.html#mvc-ann-requestmapping
类名使用大驼峰风格,但以下情形例外: DO/BO/DTO/VO/AO
方法名、参数名、成员变量、局部变量统一使用小驼峰风格
包名统一使用小写,点分隔符之间有且仅有一个自然语义的英语单词
常见命名命名风格介绍
大驼峰: 所有单词首字母都需要大写,又叫帕斯卡命名法,比如: UserController
小驼峰: 除了第一个单词,其他单词首字母大写,比如: userController
蛇形: 用下划线()作用单词间的分隔符,一般小写,又叫下划线命名法,比如: user_control
串形: 用短横线(-)作用单词间的分隔符,又叫脊柱命名法,比如: user-controller
类名使用大驼峰
变量名使用小驼峰
数据库,字段命名用蛇形
学习Spring MVC,其实就是学习各种Web开发需要用的到注解
Cookie 和Session都是会话机制,Cookie是客户端机制,Session是服务端机制.二者通过SessionId来关联,Spring MVC内置HttpServletRequest,HttpServletResponse两个对象,需要使用时,直接在方法中添加对应参数即可,Cookie和Session可以从HttpServletRequest中来获取,也可以直接使用HttpServletResponse设置Http响
状态码
Java EE学习阶段会涉及较多工具,插件的学习,来帮助我们提高开发效率,比如Postman,lombok,EditStarter
感谢各位读者的阅读,本文章有任何错误都可以在评论区发表你们的意见,我会对文章进行改正的。如果本文章对你有帮助请动一动你们敏捷的小手点一点赞,你的每一次鼓励都是作者创作的动力哦!😘
上一篇:Seal^