目录
Spring Web MVC 是什么
什么是Serlet
什么是MVC
什么是Spring MVC
使用Spring MVC
建立连接
@RequestMapping
请求
传递单个参数
传递多个参数
传递对象
后端参数重命名
传递数组
传递集合
传递JSON数据
获取url参数-@pathvariable
上传文件@RequestPart
获取Cookie
Session
获取Header
响应
返回静态页面
返回HTML代码片段
返回JSON
设置状态码
设置Header
应用分层
如何分层
MVC与三层架构的区别和联系
Spring Web MVC 是什么
Sring Web MVC就是基于 Serlet API构建的Web框架. 它从一开始就包含在Spring框架中. 也可以简称Spring MVC
什么是Serlet
Serlet它是一种实现动态页面的技术.说准确一点Serlet就是一套Java Web开发的规范,或者是技术标准. 它是不能去做任何事情的,需要有人去实现这套开发规范. 实现这套开发规范就是真正的去编写代码实现里面提到的各种功能,包括类,方法,属性.这套规范sun公司是开放的,其他公司也可以实现这套规范.现在常用的Serlet产品有Tomcat,Weblogic,Jetty等,它们都可以叫做Serlet容器.Serlet容器就是用来管理程序猿编写的serlet类.我们Spring boot中就是内置了Tomcat.
什么是MVC
MVC它是软件工程中的一种软件架构设计的模式. 它把软件系统分为模型,视图,控制器三个部分.
视图: 在应用程序这中用来和浏览器进行交互,展现数据资源.
模型: 用来处理程序中数据逻辑的部分.
控制器: 它用来决定对于视图发来的请求,需要用哪一个模型来处理,以及处理完后需要跳转回哪个视图.就是用来连接视图和模型的.
这就类似于去海底捞吃火锅:
进去服务器来接待客户点餐,点完餐后将菜单交给前厅,前厅再根据菜单要求给后厨发出指令,后厨就负责准备菜. 准备好后,前厅再告诉服务器这是为x号桌准备的.
服务器就是视图,前厅就是控制器,后厨就是模型.
什么是Spring MVC
MVC是一种构架设计模式,也是一种思想,而Spring MVC就是对MVC思想的具体实现. 除此之外,Spring MVC还是一个Web框架,所以Spring MVC是一个实现了MVC思想的web框架. 而Spring boot将Spring MVC给集成进去了. 且Spring在实现MVC的时候,也做出了一些自己的改变. 请求会直接到达控制器,让控制器来处理.
这就和饭店吃饭,有的地方是前厅来负责接待客人,帮助客人点餐,也就是Controller来负责接收客户的请求.
使用Spring MVC
因为是web框架,我们在浏览器中输入url后,我们的Spring MVC项目就可以感应到用户的请求,且给予相应.
所以我们学习Spring MVC,也就是学习如何通过游览器和用户程序进行交互.分为三个方面:
建立连接: 将客户端和Java程序连接起来,访问一个地址可以调用到我们的Spring程序.
请求: 用户请求时,会携带一些参数,在程序中我们就要想办法获取到这些参数.
响应: 执行逻辑后,就要把执行的结果返回给用户.
掌握了这三个功能,就掌握了Spring MVC.
建立连接
在Spring MVC中,我们使用@RequestMapping来实现yur路由映射,也就是浏览器连接程序的作用.
代码实现:
import org.springframework.web.bind.annotation.*;
@RequestMapping("/say")
@RestController
public class Requst {
@RequestMapping("/sayHi")
public String say1() {
return "hello, SpringMVC";
}
访问http://127.0.0.1:8080/say/sayHi就可以看到hello,SpringMVC了.
@RequestMapping
它是Spring MVC中常用的一种注解,它是用来注册接口的路由映射的. 当服务接收到请求时,路径为sayHi的请求就会调用sayHi这个方法的代码. 加上@RestConteoller,Spring才会去看这个类中方法有没有加@RequestMapping这个注解. 且@RequestMapping即可修饰类,也可以修饰方法. 访问的地址是类路径+方法路径. @RequestMapping各种请求类型都可以使用.
@RequestMapping标识类: 表示设置映射请求的请求路径的初始信息.
@RequestMapping标识方法: 表示设置映射请求路径的具体信息.
路由映射:当用户访问uer时,将用户的请求对应到应用程序中某个类的某个方法的过程就叫做路由映射.
请求
访问不同路径,就是发送不同的参数.在发送请求的同时,可能会带一些参数,我们需要知道如何传递参数到后端以及如何接受.
传递单个参数
@RequestMapping("/say")
@RestController
public class Requst {
@RequestMapping("/r11/{name}")
public String r1(String username) {
return "name: " + username;
}
注意:
url和参数名称不一致,是拿不到值的.
使用基本类型来接收参数,参数必须传,不然会报500错误.类型不匹配会报400错误,对于参数为空的数据,建议使用包装类型.
传递多个参数
@RequestMapping("/say")
@RestController
public class Requst {
@RequestMapping("/r3")
public String say3(Integer age, String name, Integer id) {
return "接收到: " + age + name + id;
}
}
当有多个参数时,前后端进行匹配时按照参数的名称来进行匹配的,所以位置不影响后端获取参数的结果.
传递对象
package com.example.demo;
import lombok.Data;
@Data
public class Student {
private String name;
private Integer age;
private int Id;
}
@RequestMapping("/say")
@RestController
public class Requst {
@RequestMapping("/r4")
public String say4(Student student) {
return "接收到: " + student;
}
}
Spring会根据参数名称来自动绑定到对象的各个属性中,如果某个参数没传递,则赋值为null,基本类型为默认值.
后端参数重命名
@RequestMapping("/say")
@RestController
public class Requst {
@RequestMapping("/r6")
public String say5(@RequestParam("name") String uername) {
return uername;
}
}
使用@RequestParam进行参数重命名时,请求参数只能和@RequestParam声明的名称一致,才能进行参数绑定和赋值.且使用@RequestParam后参数变成了必传参数.(它的required默认为true)
传递数组
@RequestMapping("/say")
@RestController
public class Requst {
@RequestMapping("/r8")
public String say8(String[] array) {
return Arrays.toString(array);
}
}
传递集合
@RequestMapping("/say")
@RestController
public class Requst {
@RequestMapping("/r9")
public String r9(@RequestParam() List<String> list) {
return "list:" +list;
}
}
集合参数和数组类似,同一个请求参数名有多个,且需要使用@RequestParam来绑定参数关系(默认情况下,请求中参数名相同的多个值是封装到数组中的)
传递JSON数据
json的数据是在键值对key和value中,数据用,分割 对象用{}, 数组用[]表示 值可以为对象,也可以为数组,数组中可以有多个对象.
@RequestBody:表示请求正文, 意思是这个注解作用在请求正文的数据绑定,请求参数必须写在请求正文中.
@RequestMapping("/r10")
public String r10(@RequestBody Student student) {
return "接收到: " + student;
}
获取url参数-@pathvariable
@pathvariable: 路径变量
这个注解作用就是将请求url路径上的数据绑定,默认是传递参数写在url上,SpringMVC就可以获取到
@RequestMapping("/r11/{name}")
public String r11(@PathVariable("name") String username) {
return "name: " + username;
}
上传文件@RequestPart
@RequestMapping("/say")
@RestController
public class Requst {
@RequestMapping("/r12")
public String r12(@RequestPart("filename") MultipartFile file) {
String filename = file.getOriginalFilename();
return "file: " + filename;
}
}
获取Cookie
传统获取cookie:
@RequestMapping("/getc")
public String getCookie(HttpServletRequest request) {
String name = request.getParameter("name");
Cookie[] cookkies = request.getCookies();
StringBuilder builder = new StringBuilder();
if (cookkies!=null){
for (Cookie ck:cookkies) {
builder.append(ck.getName()+":"+ck.getValue());
}
}
return "Cookie: " + builder;
}
HttpServletRequest,HttpServletResponse是Servlet提供的两个类,是SpringMVC的内置对象(因为Spring MVC是基于Servlet进一步封建的),需要使用时直接声明即可.
简易获取Cookie:
@RequestMapping("/getc1")
public String getCookie1(@CookieValue("bite") String bite) {
return "Cookie: " + bite;
}
Session
Session存储
@RequestMapping("/setc")
public String setsess(HttpServletRequest request) {
//getSession()是通过request中的Cookie中的SessionID来获取到对应的Session对象.
HttpSession session = request.getSession();
session.setAttribute("name", "zhangsan");
session.setAttribute("n", "zhang");
return "设置成功";
}
获取Session的两种方式:
HttpSession getSession(boolean create);
HttpSession getSession();
getSession(boolean create): 参数如果为True,则不存在会话时会创建新的会话;参数如果为false,则当不存在会话时返回null.
getSession(): 和getSession(true)含义一样,默认值为true;
Object getAttribute(String name)
返回Session会话中具有指定名称的对象,如果没有,返回null.
简易获取Session
@RequestMapping("/getSess2")
public String sess2(@SessionAttribute(value = "username",required = false)
String username) {
return "username:"+username;
}
@RequestMapping("/getSess3")
public String sess3(HttpSession session) {
String username = (String)session.getAttribute("username");
return "username:"+username;
}
获取Header
传统获取Header:
@RequestMapping("/param10")
public String param10(HttpServletRequest request, HttpServletResponse response)
{
String userAgent = request.getHeader("User-Agent");
return name + ":"+userAgent;
}
简易获取Header:
@RequestMapping("/header")
public String header(@RequestHeader("User-Agent") String userAgent) {
return "userAgent:"+userAgent;
}
RequestHeader的参数值为HTTP请求报头中的Key.
响应
Http相应结果可以是数据,也可以是静态页面,也可以针对响应设置状态码,Header信息等.
返回静态页面
我们需要将前端页面放在static包下.
后端代码访问:
@Controller
public class ResponseController {
@RequestMapping("/index")
public Object index() {
return "/index.html";
}
注意:
@RestController = Controller + ResponseBody
@Controller: 定义一个控制器, Spring框架启动时加载,把这个对象交给Spring管理
@ResponseBody: 定义返回的数据格式为非视图,返回一个text/html信息.它即可以在类上,也可以在方法上.
想要返回视图用@Controller即可.
返回HTML代码片段
后端返回数据时,如果数据中有HTML代码,也会被游览器解析:
@Controller
public class ResponseController {
@ResponseBody
@RequestMapping("/returnhtml")
public String returnhtml() {
return "<H1>我是index页面</H1>";
}
}
返回JSON
Spring MVC也可以返回JSON,后端方法返回结果为对象:
@ResponseBody
@RequestMapping("/returnjson")
public HashMap<String, String> returnjson() {
HashMap<String, String> hash = new HashMap<>();
hash.put("java", "110");
hash.put("mysql", "110");
return hash;
}
设置状态码
SpringMVC会根据我们的方法返回结果自动设置响应状态码,但也可以手动指定状态码.
@ResponseBody
@RequestMapping("/setstatus")
public Object setstatus(HttpServletResponse response) {
response.setStatus(404);
return "666";
}
设置Header
Http相应报头会向客户端传递一些附加信息,比如服务程序的名称,请求的资源已移动到新地址等.这些信息通过@RequestMapping注解的属性来实现.
@RequestMapping源码:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
@Reflective({ControllerMappingReflectiveProcessor.class})
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 {};
}
1. value: 指定映射的URL
2. method:指定请求的method类型, 如GET,POST等
3. consumes: 指定处理请求(request)的提交内容类型(Content-Type),例如application/json,
text/html;
4. produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回
5. Params:指定request中必须包含某些参数值时,才让该⽅法处理
6. headers:指定request中必须包含某些指定的header值,才能让该⽅法处理请求
设置Content-Type
@RequestMapping(value = "/returnJson2",produces = "application/json")
@ResponseBody
public String returnJson2() {
return "{\"success\":true}";
}
设置其他Header
这需要使用HttpServletResPonse提供的方法来进行设置:
@RequestMapping(value = "/setHeader")
@ResponseBody
public String setHeader(HttpServletResponse response) {
response.setHeader("MyHeader","MyHeaderValue");
return "设置Header成功";
}
应用分层
应用分层是一种设计思想,它是将应用程序分为N个层次,分别负责各自的职责,MVC设计模式就是分层的具体体现.
如何分层
这里我们将整体分为三个层次,将用户视图和业务隔离开来,通过控制器连接起来,可以很好的视线逻辑的解耦.现在流行的开发发方式是前后端分离的方式,后端开发工程师不需要关注前端的实现,我们Java后端又有了一种新的分层架构: 把整体架构分为表现层,业务逻辑层,数据层,这种分层方式称为"三层架构".
表现层(Controller): 展现数据结果和接受用户指令.
业务逻辑层(Service): 负责处理业务逻辑
数据层(Dao): 负责存储管理与应用相关的数据.
在编写代码时,我们就可以分为三个包来具体实现三层架构:
model是用来放实体类的.
MVC与三层架构的区别和联系
这两者可以说都是软件工程中的架构模式.
MVC中视图和控制器合起来对应的是三层架构中的表现层,模型对应的就是三层架构中的业务层,数据层,实体类.
这两者是从不同角度进行了抽象:
MVC强调的是数据和视图分离,将数据展示和数据处理分开,通过控制器对两者组合.而三层架构抢到的是不同维度数据处理的高内聚和低耦合,将业务处理,数据库,交互页面的逻辑分开.
但是它们两者的目的都是一样的,都是解耦,分层,代码复用.