SpringMVC
一。概念:
Spring Web MVC是一个Web框架,简称为SpringMVC
MVC定义:
MVC就是把一个项目分成三部分
MVC是一种思想,Spring进行实现,因此称为SpringMVC
SpringBoot是创建SpringMVC项目
当前时期MVC已经发生了变化,后端人员不涉及前端页面的开发,所以就没有了view层
所以View层有一种解释,之前返回的是视图,现在返回的是视图所需要的数据
java
@RequestMapping("/hhh")
public String sayHi(){
return "hehe";
}
这里的return返回的hehe就是返回的就是视图所需的数据
二。SpringMVC:
1。建立连接(客户端和服务器)
@RequestMapping. 路由映射,这个标签可以修饰方法,也可以修饰类
访问地址:类的路径+方法路径
java
@ResponseMapping("/hhh")
@RestController
public class HelloController{
@RequestMapping("/sayHi")
public String sayHi(){
return "Hi";
}
@RequestMapping("sayHello")
public String sayHello(){
return "hello";
}
}
如果想访问sayHello这个方法,只需运行然后在浏览器地址栏中输入127.0.0.1:8080/hhh/sayHello
@RequestMapping支持GET和POST请求(其实支持所有类型的请求)
java
@RequestMapping("/sayHello")
public String sayHello(){
return "hello";
}
//注解中没有写属性名,那么默认为value
@RequestMapping(value="/sayHello",method=RequestMethod.GET)
public String sayHi(){
return "Hi";
}
//注解中写method可以限制请求方式,向上面这种就是限制了只能使用GET方法
注:如果出现404原因可能是url写错了,如果出现405原因可能是使用的请求出现问
2。请求
主要就学习如何传参(发送命令)
(1)传递单个参数:
java
@RequestMapping("/m1")
public String m1(String name){
return "收到的name为:"+name;
}
这里的name不考虑是怎么得到的,怎么把数据给后端是前端要考虑的事情
要注意一点请求中的参数名要和后端的参数名一样,例如PostMan发送请求
(2)传递多个参数
java
@RequestMapping("/m2")
public String m2(String name,int age){
return "收到的参数name:"+name+",age:"+age;
}
如果使用基本类型,必须传值,不传会报错
因此如果后期在这个方法中想加入一些新的参数,或者删除一些参数,就要通知调用方(前端...)把参数传过来,这样就会很麻烦,为力解决这个问题,就要把参数进行封装,使用对象
(3)传递对象
java
@RequestMapping("/m4")
public String m4(Person person){
return "接收到的参数Person:"+person.toString();
}
java
public class Person{
Integer id;
String name;
Integer age;
//让IDEA生成一下getter和setter和toSting
}
把传入的对象封装成对象之后,代码就会变的很灵活,如果发送方(前端)没有给某个参数传值,我们可以在对象(Person)中加入一些默认值之类的逻辑,这样就算前端没有传值,代码也不会报错,可以正常运行,因此,开发中接口的参数常常 定义为对象
(4)后端参数重命名
如果前端传来的名字不合适,后端是可以对名字进行重命名的
java
@RequestMapping("/m5")
public String m5(@RequestParam("name") String username){
return "收到的参数name:"+username;
}
@RequestParam标签里的内容就是前端传来的参数名,后面的是后端想改成的名字
还有就是@RequestParam标签里的内容是必传参数,如果不传就会报错,在这个标签中也可将其设置为非必传标签
java
@RequestMapping("/m5")
public String m5(@RequestParam(value+"name",required=false) String username){
return "收到的参数name:"+username;
}
(5)传递数组
当我们请求中,同一个参数有多个值的时候,浏览器会我们给封装成一个数组
http://127.0.0.1:8080/hhh/m6?arrayName=zhangsan,lisi,wangwu
http://127.0.0.1:8080/hhh/m6?arrayName=zhangsan&arrayName=lisi&arrayName=lisi
java
@RequestMapping("/m6")
public String m6(String[] arrayName){
return "返回的参数arrayName:"+Array.toString(arrayName);
}
注:1.后端无需考虑数据是怎么传过来的,就像厨师一样,不用管用户是线上还是线下点餐,只要把菜做好就行
2.发送GET请求默认是从url的queryString中获取,如果用PostMan的Body中的x-www-...来发送GET请求,可能会导致后端拿不到参数
(6)传递集合
java
@RequestMapping("/m7")
public String m7(@RequestParam List<String> listParam){
return "接收到的参数listParam:"+listParam;
}
补充:状态码:
(1)HTTP状态码:不是后端自定义的:2xx:成功,3xx:重定向,4xx:客户端错误,5xx:服务端错误
(2)业务状态码:http响应成功的前提下,业务的响应结果分为不同的状态,例如用户登陆:密码正确200,错误-1
(7)传递JSON
正常来说,开发中上面的六种方法都不常用,最常用的就是json格式进行传递
json本质上是一个字符串,表示对象的字符串
以下几种JSON形式都是正确的
json
{"name"="zhangsan","age"=10}
[{"name"="zhangsan","age"=10},{"name"="lisi","age"=19}]
传递Json数据,需要使用@RequestBody
java
@RequestMapping("/m8")
public String m8(@RequestBody Person person){
return "接收的数据person:"+person.toString();
}
不加这个@RequestBody注解的话,person就只能从url的queryString中拿,如说Body中写json就无法被传递
(8)获取文件,图片
java
@RequestMapping("/m9")
public String m9(@RequestPart MultipartFile file){
System.out.println(file.getOriginalFilename());
return "success";
}
用postMan发送请求的时候,要选中from-data选项,并且Key中的元素要和传入的元素的参数名相同
java
@RequestMapping("/m9")
public String m9(@RequestPart MultipartFile file){
System.out.println(file.getOriginalFilename());
file.transferTo(new File("D:/temp/"+file.getOriginalFilename()));
return "success";
}
加上file.transferTo(new File("D;/temp/"+file.getOriginalFilename()));这句话就可以把文件存入到自己电脑的某个地方
(9)cookie和session
Http是无记忆功能,现在请求和过一会儿请求,同样的参数得到的结果是一致的(处理逻辑一致)
cookie:客户端 session:服务器端
举个例子来理解cookie和session:假设我去医院,要先挂号,这时医生会给我一个就诊卡,这个就诊卡就相当于cookie,就诊卡中存储的是用户的信息(身份标识),我要拿着就诊卡去各个科室,见到医生之后,医生会让我刷就诊卡,书卡这个过程,就会通过医院系统,查询我的身份标识,进一步得到完整的身份信息,显示在医生的电脑上。这里的完整的身份信息比如诊断信息,用户详细信息,以往病例...,每个用户都有一份这样的信息,这些数据在服务器上怎么组织的呢?当然是存储在数据库之中的,在服务器代码逻辑展开执行的过程中,这些数据就会被从数据库查询出来,先临时保存到某个内存结构,后续有什么修改之类的,只用修改内存,重新写入就行;这里的内存结构其实就是session
获取cookie:
法一:使用Spring内置对象(HttpServletRequest和HttpServletResponse)
java
@RequestMapping("hhh")
public String getCookie(HttpServletRequest request,HttpServletResponse response){
Cookie[] cookies=request.getCookies();
for(int i=0;i<cookies.length;i++){
System.out.pringln(cookie.getName()+":"+cookie.getValue());
}
return "获取cookie成功";
}
法二:使用@CookieValue标签
java
@RequestMapping("hh")
public String getCookie2(@CookieValue String bite){
return "cookie存储的值bite:"+bite;
}
使用标签的方法有一个坏处就是它只能一个一个cookie去拿,无法向法一一样,一次把所有cookie值拿到,通过循环去获取值,当然也可以使用一次获取多个cookie的方式,只是要多写几次cookieValue注解
java
@RequestMapping("hh")
public String getCookie2(@CookieValue String bite,@CookieValue String name,@CookieValue int age){
return "cookie存储的值bite:"+bite;
}
获取session:
法一:
java
@RequestMapping("/setSession")
public String setSession(HttpServletRequest request){
HttpSession session=request.getSession();
session.setAttribute("username","zhangsan");
return "success";
}
@RequestMapping("/getSession")
public String getSession(HttpServletRequest request){
HttpSession session=request.getSession(false);
if(session!=null){
String username=(String)session.getAttribute("username");
return "用户登陆"+username;
}
return "sesseion为空";
}
这个写法和Servlet几乎是一样的
法二:
java
@RequestMapping("hhh")
public String getSession1(@SessionAttribute String username){
return "username"+username;
}
使用这种注解的方法可以迅速的从session中获取到想要的参数
法三:
java
@RequestMapping("hhihih")
public String getSession3(HttpSession session){
String username=(String)session.getAttribute("username");
}
getSession3方法中的参数HttpSession session就等价于HttpSession session=request.getSession(true);
3。响应
(1)返回静态页面:
在resource文件夹下有一个static文件夹,在这个文件夹放入要写的前端代码
java
@Controller
public class ReturnController{
@RequestMapping("/index")
public String returnIndex(){
return "/index.html";//请求到static文件夹中找到这个文件
}
}
Controller的作用就是告诉Spring帮我们管理代码,@controller返回的是视图,随着前后端端分离,后端不在处理页面,只返回页面所需的数据,因此经常使用@ResponseBody,而@RestController是两者的结合体
(2)返回Json
当我们的接口返回的是String,Int,double...时,content-type时text/html
当我们接口返回的是对象,map的时候,content-type自动设置为application/json
三。综合性练习:
1.加法计算器:
前端代码:
html
后端代码:
java
@RequestMapping("/hhh")
@RestController
public class calcController{
@RequestMapping("/sum")
public String sum(Integer num1,Integer num2){
int sum=num1+num2;
return "计算结果为:"+sum;
}
}
2.登陆案例:
(1)登陆接口:/user/login
userName=?&password=?
接口返回:true密码正确,false密码错误
(2)获取用户的登陆信息:/user/getUserInfo
接口返回:当前登陆用户的名称
java
@RequestMapping("/user")
@RestController
public class UserController{
@RequestMapping("/login")
public Boolean login(String username,String password,HttpSession session){
//step1:先判断传进来的username和password是否合法
if(!StringUtils.hasLength(username)||!StringUtils.hasLength(password)){
return false;
}
//step2:进行账号和密码的校验
if("zhangsan".equals(username)&&"edg".equals(password)){
session.setAttribute("username","zhangsan");
return true;
}
return false;
}
@RequestMapping("/getUserInfo")
public String getUserInfo(HttpServletRequest request){
HttpSession session=request.getSession("false");
String username=null;
if(session!=null){
userName=(String)session.getAttribute("username");
}
return userName;
}
}
3.留言板案例:
前端没有保存数据的能力,后端要把数据保存下来,由于目前还还没学如何和数据库建立连接,所以就使用回文的方式,将数据放到内存中
接口定义:
提交留言:/message/publish ,参数:MessageInfo(from,to,message),返回结果:true/false
查看所有留言:/message/getMessageList,参数:无,返回结果:List
前端:
后端:
java
public class MessageInfo{
private String from;
private String To;
private String message;
//用IDEA生成以下setter和getter和toString
}
java
@RequestMapping("/message")
@RestController
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("/getMessageInfo")
public List<MessageInfo> getMessageInfo(){//查看所有留言
return messageInfos
}
}
4.图书管理系统:
现在就只完成图书管理系统的两个功能,登陆(用户输入账号,密码完成登陆)和列表(展示图书),剩下的功能以后回专门写一篇博客
定义前后端交互的接口:
1.登陆:
URL:/user/login。 参数:userName=?&password=? 响应:true/false
2.图书列表展示:
URL:/book/getBookList。 参数:无。 响应:List
后端:
(1)BookInfo文件:
java
@Data
public class BookInfo{
private Integer id;
private String bookName;
private String author;
private Integer count;
private BigDecimal price;//这个类型是专门用来对价格进行修饰的
private String publish;
private Interger status;//1-可借 2-不可借
private String statusCN;
}
(2)UserController文件:
java
@RequestMapping("user")
public class UserController{
@RequestMapping("login")
public Boolean login(String username,String password,HttpSession session){
if(!StringUtils.hasLength(username)||!StringUtils.hasLength(password)){
return false;
}
if("zhangsan".equals(username)&&"edg".equals(password)){
session.setAtrribute("username",username);
return true;
}
return false;
}
}
(3)BookController文件:
一共有三步:获取图书数据->对图书数据进行处理->返回数据
由于目前还没学连接数据库,那么就要造一些假数据,来协助后端完成代码
java
@RestController
public class BookController{
@RequestMapping("/getBookList")
List<BookInfo> bookInfos=mockData();//mock表示虚拟的意思,假数据
for(int i=0;i<bookInfos.length();i++){
if(bookInfos.get(i).getStatus()==1){
bookInfo.setStatusCN("可借");
}else{
bookInfo.setStatusCN("不可借");
}
}
}
private List<BookInfo> mockData(){
List<BookInfo> 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(100));
bookInfo.setPrive(new BigDecimal(new Random().nextInt(100)));
bookInfo.setPublish("出版社"+i);
bookInfo.setStatus(i%5==0?2:1);
bookInfos.add(bookInfo)l;
}
return bookInfos;
}