目录
三大框架底层源码超详细总结 (二)SpringMVC (面试必备)
SpringMVC介绍
springmvc优势
一、什么是MVC框架
二、SpringMVC执行流程
1.服务器启动的时候做了什么
2.服务器启动完之后做了什么
3原理图
4.SpringMVC常用注解
5.SpringMVC主要组件
6.接收数据(前端)
6.1 通过设置String userName,String userPassword 传值的方式
6.2通过注解方式@RequestParam
6.3通过JaveBean对象
6.4通过超链接传输方式 aaa
7.返回数据(客户端)
7.1通过用ModelAndView 把数据存储给Model,把view 存储给View(只能给浏览器)
7.2通过String代替View+Model参数位置任意 ,用来存储Model的数据
7.3通过String代替View+modelMap代表的是Model
7.4通过String代替View+Map代表的是Model
7.5借助jackson把java对象转换json字符串,并响应给客户端(可跨平台)
7.6程序员先把users对象转换json字符串 用response对象把json字符串响应给客户端(可跨平台)
小总结:
8过滤器和拦截器的区别
9.springmvc与struts2本质不同
10支持的数据类型
首先简单介绍什么是MVC架构 三大框架很好的解释MVC架构的用法,传统的MVC模式(Model-view-controller)是软件工程中的一种软件架构,即把软件系统分为了三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
控制器(Controller) - 负责转发请求,对请求进行处理。
视图(View) - 界面设计人员进行图形界面设计。
模型(Model) -程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)。
传统的MVC框架还是存在着一定的耦合性,比如模型层夹杂着业务层和数据库的访问,所以SpringMVC把传统的模型层拆分为了业务层(Service)和数据访问层(DAO,Data Access Object)。在Service下可以通过Spring的声明式事务操作数据访问层,而在业务层上还允许我们访问NoSQL,这样能满足现代互联网系统的性能。Spring MVC其最大的特点就是结构松散,耦合度较低,对各个模块进行了分离,使得各个层负责各个层的逻辑,开发起来更加清晰。
1、清晰的角色划分:前端控制器(DispatcherServlet)、请求到处理器映射(HandlerMapping)、处理器适配器(HandlerAdapter)、视图解析器(ViewResolver)、处理器或页面控制器(Controller)、验证器( Validator)、命令对象(Command 请求参数绑定到的对象就叫命令对象)、表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要;
3、由于命令对象就是一个POJO,无需继承框架特定API,可以使用命令对象直接作为业务对象;
4、和Spring 其他框架无缝集成,是其它Web框架所不具备的;
5、可适配,通过HandlerAdapter可以支持任意的类作为处理器;
6、可定制性,HandlerMapping、ViewResolver等能够非常简单的定制;
7、功能强大的数据验证、格式化、绑定机制;
8、利用Spring提供的Mock对象能够非常简单的进行Web层单元测试;
9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
10、强大的JSP标签库,使JSP编写更容易。
还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等。
Spring Web MVC是spring提供给Web应用的框架设计。实际上MVC框架是一个设计理念,它不仅存在于Java世界中,它的流程是各个组件的应用和改造SpringMVC的根本。所以要了解SpringMVC,首先是要了解SringMVC的流程和各个组件。
https://blog.csdn.net/LiuY521/article/details/90048542 我在之前博客里面有介绍 面试会问
1.Tomcat启动的时候会自我检查,会自动读取本身的Web.xml文件,加载里面配置的信息,开启服务,开启引擎
2.开启引擎,并逐一扫描每一个Web项目的xml文件,并为其配置有且只有一个ServletContext
3.监听器读取Spring的配置文件,并初始化Spring容器
4.过滤器生命周期开始
5.DispatcherServlet(前端控制器)生命周期开始,
6.tocmat启动完毕
7.客户端发送请求,根据后缀,被DispatcherServlet拦截,进入其service方法
8.service方法截取请求url的字符串获取有效的url,
9.service用url去寻找spring mvc子容器handlerMpping中的map集合中的映射关系(读取方法) 返回给service
10.service用有效的映射关系,去springmvc子容器中得到指定Controller对象, 并用HandlerAdaper反射调用映射指定的方法,把方法的返回值给service方法
11.service接收到了Model数据和View的页面名称,把ModelAndView(视图解析器)送给内部资源视图解析器 把Model数据渲染到页面上,view值拼装响应的url,并把渲染后的数据返回service方法
12service方法把数据响应给客户端,service调用完毕,以后循环往复.
springMVC的常用注解
@Controller 相当于
@Autowired 根据类自动注入属性
@RequestMapping 指定请求路径
@RequestParam 给方法形参赋值时指定表单参数名称
@PathVaribale 用于restful风格的请求
@ResponseBody 返回json格式的数据
@Value 读取配置的常量
......
1.前端控制器DispatcherServlet(不需要程序员开发)。
作用:接收请求,响应结果,相当于转发器,中央处理器。有了DispatcherServlet减少了其它组件之间的耦合度。
2.处理器映射器HandlerMapping(不需要程序员开发)。
作用:根据请求的url查找Handler。
3.处理器适配器HandlerAdapter(不需要程序员开发)。
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler。
4.处理器Handler(需要程序员开发)。
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
5.视图解析器ViewResolver(不需要程序员开发)。
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
6.视图View(需要程序员开发jsp)。
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
【注】:不需要程序员开发的,需要程序员自己做一下配置即可。
@Controller
public class UserController {
/**
* 接收客户端提交的数据
* 要求名称必须精确一对一匹配
* @param userName
* @param userPassword
* @return
*/
@RequestMapping(value="user/login1.do",method=RequestMethod.POST)
public ModelAndView login1(String userName,String userPassword){
System.out.println(userName+" "+userPassword);
ModelAndView mav=new ModelAndView();
//假设此处调用业务,此处忽略业务
mav.addObject("key", "value");
//设置一个名称,用于springmvc拼装响应的url 前缀+success+后缀
mav.setViewName("success");
return mav;
}
/**
*
* @param name @RequestParam(value="userName",required=true) String name
*
* @param pwd @RequestParam("userPassword")String pwd
*
* @return
*/
@RequestMapping(value="user/login2.do",method=RequestMethod.POST)
public ModelAndView login2(
@RequestParam(value="userName",required=true) String name,
@RequestParam("userPassword")String pwd){
System.out.println(name+" "+pwd);
ModelAndView mav=new ModelAndView();
//假设此处调用业务,此处忽略业务
mav.addObject("key", "value");
//设置一个名称,用于springmvc拼装响应的url 前缀+success+后缀
mav.setViewName("success");
return mav;
}
/**
*
* @param user 把name="userName" -->setUserName 去User对象中找是否此方法,有就反射调用
* 把name="userPassword" -->setUserPassword 去User对象中找是否此方法,有就反射调用
* @return
*/
@RequestMapping(value="user/login3.do",method=RequestMethod.POST)
public ModelAndView login3(User user){
System.out.println(user.getUserName()+" "+user.getUserPassword());
ModelAndView mav=new ModelAndView();
//假设此处调用业务,此处忽略业务
mav.addObject("key", "value");
//设置一个名称,用于springmvc拼装响应的url 前缀+success+后缀
mav.setViewName("success");
return mav;
}
@RequestMapping(value="user/login4.do",method=RequestMethod.GET)
public ModelAndView login4(String name,String pwd){
System.out.println(name+" "+pwd);
ModelAndView mav=new ModelAndView();
//假设此处调用业务,此处忽略业务
mav.addObject("key", "value");
//设置一个名称,用于springmvc拼装响应的url 前缀+success+后缀
mav.setViewName("success");
return mav;
}
@Controller
public class UserController2 {
/**
* 用ModelAndView 把数据存储给Model,把view 存储给View
* @param userName
* @param userPassword
* @return ModelAndView
*/
@RequestMapping(value="user2/login1.do",method=RequestMethod.POST)
public ModelAndView login1(String userName,String userPassword){
System.out.println(userName+" "+userPassword);
ModelAndView mav=new ModelAndView();
//假设此处调用业务,此处忽略业务
//假设业务返回的数据为一个集合
User user1=new User(1,"aa","aa");
User user2=new User(2,"bb","bb");
User user3=new User(3,"cc","cc");
ArrayList users=new ArrayList();
users.add(user1);
users.add(user2);
users.add(user3);
/**
* 把数据存储给model
* 此写法为转发
* 等同于
* request.setAttribure("allUsers",users);
* request.getRequestDispatcher("WEB-INF/pages/success.jsp").forward(request,response);
*/
mav.addObject("allUsers", users);
//设置一个名称,用于springmvc拼装响应的url 前缀+success+后缀
mav.setViewName("success");
return mav;
}
/**
*
* @param userName
* @param userPassword
* @param model 参数位置任意 ,用来存储Model的数据
* @return String 代表view
*/
@RequestMapping(value="user2/login2.do",method=RequestMethod.POST)
public String login2(
String userName,
String userPassword,
Model model){
System.out.println(userName+" "+userPassword);
String result="error";
//假设此处调用业务,此处忽略业务
//假设业务返回的数据为一个集合
User user1=new User(1,"aa","aa");
User user2=new User(2,"bb","bb");
User user3=new User(3,"cc","cc");
ArrayList users=new ArrayList();
users.add(user1);
users.add(user2);
users.add(user3);
/**
* 把数据存储给model
* 此写法为转发
* 等同于
* request.setAttribure("allUsers",users);
* request.getRequestDispatcher("WEB-INF/pages/success.jsp").forward(request,response);
*/
model.addAttribute("allUsers", users);
//设置一个名称,用于springmvc拼装响应的url 前缀+success+后缀
result="success";
return result;
}
/**
*
* @param userName
* @param userPassword
* @param modelMap 代表的是Model
* @return 代表的view
*/
@RequestMapping(value="user2/login3.do",method=RequestMethod.POST)
public String login3(
String userName,
String userPassword,
ModelMap modelMap){
System.out.println(userName+" "+userPassword);
String result="error";
//假设此处调用业务,此处忽略业务
//假设业务返回的数据为一个集合
User user1=new User(1,"aa","aa");
User user2=new User(2,"bb","bb");
User user3=new User(3,"cc","cc");
ArrayList users=new ArrayList();
users.add(user1);
users.add(user2);
users.add(user3);
/**
* 把数据存储给model
* 此写法为转发
* 等同于
* request.setAttribure("allUsers",users);
* request.getRequestDispatcher("WEB-INF/pages/success.jsp").forward(request,response);
*/
modelMap.addAttribute("allUsers", users);
//设置一个名称,用于springmvc拼装响应的url 前缀+success+后缀
result="success";
return result;
}
@RequestMapping(value="user2/login4.do",method=RequestMethod.POST)
public String login4(
String userName,
String userPassword,
Map map){
System.out.println(userName+" "+userPassword);
String result="error";
//假设此处调用业务,此处忽略业务
//假设业务返回的数据为一个集合
User user1=new User(1,"aa","aa");
User user2=new User(2,"bb","bb");
User user3=new User(3,"cc","cc");
ArrayList users=new ArrayList();
users.add(user1);
users.add(user2);
users.add(user3);
/**
* 把数据存储给model
* 此写法为转发
* 等同于
* request.setAttribure("allUsers",users);
* request.getRequestDispatcher("WEB-INF/pages/success.jsp").forward(request,response);
*/
map.put("allUsers", users);
//设置一个名称,用于springmvc拼装响应的url 前缀+success+后缀
result="success";
return result;
}
@RequestMapping(value="user2/login5.do",method=RequestMethod.GET)
@ResponseBody//借助jackson把java对象转换json字符串,并响应给客户端
public Result login5(
String userName,
String userPassword){
System.out.println(userName+" "+userPassword);
Result result=new Result();
//假设此处调用业务,此处忽略业务
//假设业务返回的数据为一个集合
User user1=new User(1,"aa","aa");
User user2=new User(2,"bb","bb");
User user3=new User(3,"cc","cc");
ArrayList users=new ArrayList();
users.add(user1);
users.add(user2);
users.add(user3);
result.setStatus(1);
result.setMessage("登录成功!!");
result.setData(users);
return result;
}
@RequestMapping(value="user2/login5_1.do",method=RequestMethod.GET)
public void login5_1(
String userName,
String userPassword,
HttpServletRequest request,
HttpServletResponse response){
System.out.println(userName+" "+userPassword);
Result result=new Result();
//假设此处调用业务,此处忽略业务
//假设业务返回的数据为一个集合
User user1=new User(1,"aa","aa");
User user2=new User(2,"bb","bb");
User user3=new User(3,"cc","cc");
ArrayList users=new ArrayList();
users.add(user1);
users.add(user2);
users.add(user3);
result.setStatus(1);
result.setMessage("登录成功!!");
result.setData(users);
//程序员自己先把users对象转换成json字符串
//用response对象吧json字符串响应给客户端
String jsonString=JSON.toJSONString(result);
System.out.println("jsonString="+jsonString);
try {
//设置response响应消息头
response.setContentType("text/json;charset=UTF-8");
//构建响应的输出流
PrintWriter out=response.getWriter();
//把json字符串的内容响应给客户端
out.println(jsonString);
out.flush();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
在实际开发中
接收数据 1,2,3,4
返回数据 1.2.3.4.(字符串只适合浏览器)5.6(json可跨平台)多用json
1.springmvc入口是一个servlet前端控制器(DispatcherServlet),struts2入口是一filter过滤器(StrutsPrepareAndExecuteFilter).
2.struts2通过在action类中定义成员变量接收参数,(属性驱动和模型驱动),它只能使用多例模式管理action.
springmvc通过在coontroller方法中定义形参接收参数,springmvc可以使用单例模式管理controller.
3.springmvc是基于方法开发的,注解开发中使用requestMapping将url和方法进行 映射,如果根据url找到controller类的方法生成 一 个handler处理器对象(只包括一个method).
struts2是基于类开发的,每个请求过来创建一个action实例,实例对象中有若干个方法.
开发中建议使用springmvc,springmvc方法更类似service业务方法.
4.struts2采用值栈存储请求和相应的数据,通过OGNL存取数据,springmvc通过参数绑定期将request请求内容解析,并给方法形参赋值.
5.struts2和springmvc的速度是相当的,由于struts2的漏洞较多,跟多企业使用springmvc
struts2:底层是Servlet,参数基于属性封装,如果配置单例,会出现线程安全问题,所以配置多例
springmvc:底层是Servlet,单例
6. 参数封装
struts2:基于属性封装
springmvc:基于方法进行封装